<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>M3G File Format</title>
    <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type" />
    <link href="stylesheet.css" rel="stylesheet" title="Style" type="text/css" />
</head>
<body>
    <h1>
        File Format for Mobile 3D Graphics API</h1>
    <h2 class="SectionTitle">
        Abstract</h2>
    <p>
        This specification defines a 3D Graphics File Format that complements the Mobile
        3D Graphics API
        <v2>version 2.0 (M3G2)</v2>
        . The file format is provided as a compact and standardised way of populating a
        scene graph.
        <v2>It builds on the file format defined for M3G 1.0 and 1.1, so that a single
        loader can easily be constructed that will load both formats with minimal overhead.</v2>
    </p>
    <h2 class="SectionTitle">
        Contents</h2>
    <ul>
        <li><a href="#ImportantNotes">1 Important Notes</a></li>
        <li><a href="#MimeType">2 MIME Type and File Extension</a></li>
        <li><a href="#DataTypes">3 Data Types</a>
            <ul>
                <li><a href="#FundamentalDataTypes">3.1 Fundamental Data Types</a></li>
                <li><a href="#CompoundDataTypes">3.2 Compound Data Types</a></li>
            </ul>
        </li>
        <li><a href="#FileStructure">4 File Structure</a></li>
        <li><a href="#FileIdentifier">5 File Identifier</a></li>
        <li><a href="#Section">6 Section</a>
            <ul>
                <li><a href="#CompressionScheme">6.1 CompressionScheme</a></li>
                <li><a href="#TotalSectionLength">6.2 TotalSectionLength</a></li>
                <li><a href="#UncompressedLength">6.3 UncompressedLength</a></li>
                <li><a href="#Objects">6.4 Objects</a></li>
                <li><a href="#Checksum">6.5 Checksum</a></li>
            </ul>
        </li>
        <li><a href="#ObjectStructure">7 Object Structure</a>
            <ul>
                <li><a href="#ObjectType">7.1 ObjectType</a></li>
                <li><a href="#ObjectLength">7.2 Length</a></li>
                <li><a href="#ObjectData">7.3 Data</a></li>
            </ul>
        </li>
        <li><a href="#ObjectOrdering">8 Object Ordering</a>
            <ul>
                <li><a href="#ObjectReferences">8.1 Object References</a></li>
                <li><a href="#SharedObjects">8.2 Shared Objects</a></li>
                <li><a href="#CyclicReferences">8.3 Cyclic References</a></li>
                <li><a href="#SubtreeLoading">8.4 Subtree Loading</a></li>
            </ul>
        </li>
        <li><a href="#ErrorHandling">9 Error Handling</a></li>
        <li><a href="#SpecialObjectData">10 Special Object Data</a>
            <ul>
                <li><a href="#Header">10.1 Header Object</a></li>
                <li><a href="#ExternalReference">10.2 External Reference</a></li>
                <li><a href="#ExternalReferenceImage">10.3 External Image Reference</a></li>
                <li><a href="#ExternalReferenceObject">10.4 External Object Reference</a></li>
            </ul>
        </li>
        <li><a href="#PerClassData">11 Per-Class Data for Format 1.0</a>
            <ul>
                <li><a href="#AnimationController">11.1 AnimationController</a></li>
                <li><a href="#AnimationTrack">11.2 AnimationTrack</a></li>
                <li><a href="#Appearance">11.3 Appearance</a></li>
                <li><a href="#Background">11.4 Background</a></li>
                <li><a href="#Camera">11.5 Camera</a></li>
                <li><a href="#CompositingMode">11.6 CompositingMode</a></li>
                <li><a href="#Fog">11.7 Fog</a></li>
                <li><a href="#Graphics3D">11.8 Graphics3D</a></li>
                <li><a href="#Group">11.9 Group</a></li>
                <li><a href="#Image2D">11.10 Image2D</a></li>
                <li><a href="#IndexBuffer">11.11 IndexBuffer</a></li>
                <li><a href="#KeyframeSequence">11.12 KeyframeSequence</a></li>
                <li><a href="#Light">11.13 Light</a></li>
                <li><a href="#Loader">11.14 Loader</a></li>
                <li><a href="#Material">11.15 Material</a></li>
                <li><a href="#Mesh">11.16 Mesh</a></li>
                <li><a href="#MorphingMesh">11.17 MorphingMesh</a></li>
                <li><a href="#Node">11.18 Node</a></li>
                <li><a href="#Object3D">11.19 Object3D</a></li>
                <li><a href="#PolygonMode">11.20 PolygonMode</a></li>
                <li><a href="#RayIntersection">11.21 RayIntersection</a></li>
                <li><a href="#SkinnedMesh">11.22 SkinnedMesh</a></li>
                <li><a href="#Sprite3D">11.23 Sprite3D</a></li>
                <li><a href="#Texture2D">11.24 Texture2D</a></li>
                <li><a href="#Transform">11.25 Transform</a></li>
                <li><a href="#Transformable">11.26 Transformable</a></li>
                <li><a href="#TriangleStripArray">11.27 TriangleStripArray</a></li>
                <li><a href="#VertexArray">11.28 VertexArray</a></li>
                <li><a href="#VertexBuffer">11.29 VertexBuffer</a></li>
                <li><a href="#World">11.30 World</a></li>
            </ul>
        </li>
        <li><a href="#PerClassData20">12 Per-Class Data for Format 2.0</a>
            <ul>
                <li><a href="#AnimationEvent">12.1 AnimationEvent</a></li>
                <li><a href="#AppearanceBase">12.2 AppearanceBase</a></li>
                <li><a href="#Blender">12.3 Blender</a></li>
                <li><a href="#Collisions">12.4 Collisions</a></li>
                <li><a href="#DynamicImage2D">12.5 DynamicImage2D</a></li>
                <li><a href="#FragmentShader">12.6 FragmentShader</a></li>
                <li><a href="#ImageBase">12.7 ImageBase</a></li>
                <li><a href="#ImageCube">12.8 ImageCube</a></li>
                <li><a href="#PointSpriteMode">12.9 PointSpriteMode</a></li>
                <li><a href="#RenderPass">12.10 RenderPass</a></li>
                <li><a href="#RenderTarget">12.11 RenderTarget</a></li>
                <li><a href="#Shader">12.12 Shader</a></li>
                <li><a href="#ShaderAppearance">12.13 ShaderAppearance</a></li>
                <li><a href="#ShaderException">12.14 ShaderException</a></li>
                <li><a href="#ShaderProgram">12.15 ShaderProgram</a></li>
                <li><a href="#ShaderUniforms">12.16 ShaderUniforms</a></li>
                <li><a href="#ShaderVariable">12.17 ShaderVariable</a></li>
                <li><a href="#Stencil">12.18 Stencil</a></li>
                <li><a href="#Texture">12.19 Texture</a></li>
                <li><a href="#TextureCombiner">12.20 TextureCombiner</a></li>
                <li><a href="#TextureCube">12.21 TextureCube</a></li>
                <li><a href="#VertexShader">12.22 VertexShader</a></li>
            </ul>
        </li>
        <li><a href="#ObjectTypeValues">13 ObjectType Values</a></li>
    </ul>
    <h2 class="SectionTitle" id="ImportantNotes">1 Important Notes</h2>
    <p>
        The data here are <i>not</i> serialized by Java's own serialization mechanism. They
        are serialized by the M3G serialization mechanism, which produces and loads data
        streams conforming to the M3G file format specification.</p>
    <p>
        For more details of the mechanisms for loading an M3G compliant file, please refer
        to the documentation for the <a href="javax/microedition/m3g/Loader.html">Loader</a>
        class.</p>
    <h2 class="SectionTitle" id="MimeType">2 MIME Type and File Extension</h2>
    <p>
        The MIME type for this file format is <tt>application/m3g</tt>. The file extension
        (for systems that do not support MIME type queries) is <tt>.m3g</tt>, to match the
        lowest level name in the package hierarchy.</p>
    <h2 class="SectionTitle" id="DataTypes">3 Data Types</h2>
    <h3 id="FundamentalDataTypes">3.1 Fundamental Data Types</h3>
    <p>
        There are several data types which are regarded as fundamental. These are as follows:</p>
    <blockquote>
        <table border="1" cellpadding="3" cellspacing="0" class="Table" width="90%">
            <tbody>
                <tr>
                    <th class="TableHead" width="20%">
                        Type Name</th>
                    <th class="TableHead" width="80%">
                        Description</th>
                </tr>
                <tr>
                    <td class="TableText">
                        <tt>Byte</tt></td>
                    <td class="TableText">
                        A single, unsigned 8-bit byte.</td>
                </tr>
                <tr class="v2">
                    <td class="TableText">
                        <tt>SByte</tt></td>
                    <td class="TableText">
                        A single, signed 8-bit byte.</td>
                </tr>
                <tr>
                    <td class="TableText">
                        <tt>Int16</tt></td>
                    <td class="TableText">
                        A signed 16 bit value, stored as two bytes, lower byte first.
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        <tt>UInt16</tt></td>
                    <td class="TableText">
                        An unsigned 16 bit value, stored as two bytes, lower byte first.
                        <v2>This is equivalent to a notional "unsigned short" type in Java. It represents a non-negative integer in the range 0 to 2<sup>16</sup>-1.</v2>
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        <tt>Int32</tt></td>
                    <td class="TableText">
                        A signed 32 bit value, stored as four bytes, lowest byte first.
                        <v2>This can be used to represent a 32-bit bitfield, if the top bit is taken to have a value of -2<sup>31</sup>.</v2>
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        <tt>UInt32</tt></td>
                    <td class="TableText">
                        An unsigned 32 bit value, stored as four bytes, lowest byte first.
                        <v2>This is <em>not</em> exactly equivalent to a notional "unsigned int" type in Java. It represents the range of non-negative values that can be assigned to an "int". These are in the range 0 to 2<sup>31</sup>-1, <em>not</em> 2<sup>32</sup>-1.</v2>
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        <tt>Float32</tt></td>
                    <td class="TableText">
                        A single precision floating point value, in 32-bit format as defined by IEEE-754.
                        This is stored as four bytes, with the least significant byte of the mantissa first,
                        and the exponent byte last.
                        <br />
                        Note that only normal numeric values and positive 0 can be stored. Special values
                        such as denormals, infinities, NaNs, negative 0, and indefinite values are disallowed
                        and must be treated as errors.
                    </td>
                </tr>
                <tr class="v2">
                    <td class="TableText">
                        <tt>Float16</tt></td>
                    <td class="TableText">
                        A half-precision floating point value, in 16-bit format as defined by IEEE-754R.
                        This is stored as two bytes, with the least significant byte of the mantissa first,
                        and the exponent byte last.
                        <br />
                        Note that only normal numeric values and positive 0 can be stored. Special values
                        such as denormals, infinities, NaNs, negative 0, and indefinite values are disallowed
                        and must be treated as errors.
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        <tt>String</tt></td>
                    <td class="TableText">
                        A null-terminated Unicode string, coded as UTF-8.
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        <tt>Boolean</tt></td>
                    <td class="TableText">
                        A single byte with the value 0 (false) or 1 (true). Other values are disallowed
                        and must be treated as errors.
                    </td>
                </tr>
            </tbody>
        </table>
    </blockquote>
    <h3 id="CompoundDataTypes">3.2 Compound Data Types</h3>
    <p>
        In order to avoid having to repeatedly specify sequences of the same types many
        times, some compound data types are defined for convenience. The composition of
        these is listed to show both their makeup and the order in which the simple elements
        are to be serialized. These are as follows:</p>
    <blockquote>
        <table border="1" cellpadding="3" cellspacing="0" class="Table" width="90%">
            <tbody>
                <tr>
                    <th class="TableHead" width="20%">
                        Type Name</th>
                    <th class="TableHead" width="60%">
                        Description</th>
                    <th class="TableHead" width="20%">
                        Composition</th>
                </tr>
                <tr>
                    <td class="TableText">
                        Vector3D</td>
                    <td class="TableText">
                        A 3D vector.</td>
                    <td>
                        <tt>Float32 x;</tt>
                        <br />
                        <tt>Float32 y;</tt>
                        <br />
                        <tt>Float32 z;</tt>
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        Matrix</td>
                    <td class="TableText">
                        A 4x4 generalized matrix. The 16 elements of the matrix are output in the same order
                        as they are retrieved using the API Transform.get method. In other words, in this
                        order:
                        <blockquote>
                            <pre>  0  1  2  3<br />  4  5  6  7<br />  8  9  10 11<br />  12 13 14 15</pre>
                        </blockquote>
                    </td>
                    <td>
                        <tt>Float32 elements[16];</tt></td>
                </tr>
                <tr>
                    <td class="TableText">
                        ColorRGB</td>
                    <td class="TableText">
                        A color, with no alpha information. Each component is scaled so that 0x00 is 0.0,
                        and 0xFF is 1.0.
                    </td>
                    <td>
                        <tt>Byte red;</tt>
                        <br />
                        <tt>Byte green;</tt>
                        <br />
                        <tt>Byte blue;</tt>
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        ColorRGBA</td>
                    <td class="TableText">
                        A color, with alpha information. Each component is scaled so that 0x00 is 0.0, and
                        0xFF is 1.0. The alpha value is scaled so that 0x00 is completely transparent, and
                        0xFF is completely opaque.
                    </td>
                    <td>
                        <tt>Byte red;</tt>
                        <br />
                        <tt>Byte green;</tt>
                        <br />
                        <tt>Byte blue;</tt>
                        <br />
                        <tt>Byte alpha;</tt>
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        ObjectIndex</td>
                    <td class="TableText">
                        The index of a previously encountered object in the file. Although this is serialized
                        as a single unsigned integer, it is included in the compound type list because of
                        the additional semantic information embodied in its type. A value of 0 is reserved
                        to indicate a null reference; actual object indices start from 1. Object indices
                        must refer only to null or to an object which has already been created during the
                        input deserialization of a file - they must be less than or equal to the index of
                        the object in which they appear. Other values are disallowed and must be treated
                        as errors.
                    </td>
                    <td>
                        <tt>UInt32 index;</tt></td>
                </tr>
                <tr>
                    <td class="TableText">
                        <v2>ForwardIndex</v2>
                    </td>
                    <td class="TableText">
                        <v2>The index of an object in the file, <em>which may not
            yet have been encountered</em>. Although this is serialized as
            a single unsigned integer, it is included in the compound
            type list because of the additional semantic information
            embodied in its type. A value of 0 is reserved to indicate
            a null reference; actual object indices start from 1.
            Object indices must refer only to null or to an object which
            exists (or will exist) during the input deserialization of a
            file - they must be less than or equal to the maximum object
            index in the file in which they appear. Other values are
            disallowed and must be treated as errors. We do not declare
            all indices in the file format as ForwardIndexes, because
            the overhead for fixing up a generalized forward reference
            can be expensive. We therefore reserve this type for cases where
            it is really necessary. During serialization of an M3G 1.0 file,
            a ForwardIndex behaves exactly like an ObjectIndex, 
            i.e. it may not reference forward.</v2>
                    </td>
                    <td>
                        <tt>
                            <v2>UInt32 index;</v2>
                        </tt>
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        <i>Type</i>[]</td>
                    <td class="TableText">
                        A variable-length array of any type is always output in a counted form, with the
                        count first. Each element is then output in index order, starting from 0. The last
                        element has index (count-1). If the array is empty, then only a 0 count is output.
                    </td>
                    <td>
                        <tt>UInt32 count;</tt>
                        <br />
                        <i>Type</i> <tt>arrayValue[0];</tt>
                        <br />
                        <i>Type</i> <tt>arrayValue[1];</tt>
                        <br />
                        <i>...etc.</i>
                    </td>
                </tr>
                <tr>
                    <td class="TableText">
                        <i>Type</i>[<i>count</i>]</td>
                    <td class="TableText">
                        Arrays with an explicit length are either always have the same constant number of
                        elements, or this count is specified elsewhere, so only the elements are output.
                        Each element is then output in index order, starting from 0. The last element has
                        index (count-1). If the array is empty, then nothing is output.
                    </td>
                    <td>
                        <i>Type</i> <tt>arrayValue[0];</tt>
                        <br />
                        <i>Type</i> <tt>arrayValue[1];</tt>
                        <br />
                        <i>...etc.</i>
                    </td>
                </tr>
            </tbody>
        </table>
    </blockquote>
    <h2 class="SectionTitle" id="FileStructure">4 File Structure</h2>
    <p>
        The file consists of the file identifier, followed by one or more sections. Thus
        the overall file structure looks like this:</p>
    <blockquote>
        <table border="1" cellpadding="3" cellspacing="0" class="Table">
            <tbody>
                <tr>
                    <td>
                        &nbsp;</td>
                    <td>
                        File Identifier</td>
                </tr>
                <tr>
                    <td>
                        Section 0</td>
                    <td>
                        File Header Object</td>
                </tr>
                <tr>
                    <td>
                        Section 1</td>
                    <td>
                        External Reference Objects</td>
                </tr>
                <tr>
                    <td>
                        Section 2</td>
                    <td>
                        Scene Objects</td>
                </tr>
                <tr>
                    <td>
                        Section 3</td>
                    <td>
                        Scene Objects</td>
                </tr>
                <tr>
                    <td>
                        ...</td>
                    <td>
                        ...</td>
                </tr>
                <tr>
                    <td>
                        Section <i>n</i></td>
                    <td>
                        Scene Objects</td>
                </tr>
            </tbody>
        </table>
    </blockquote>
    <p>
        The reason for having different sections is that some of the objects, such as the
        mesh objects, should be compressed to reduce file size, whereas other objects, such
        as the header object, should not be compressed. The header object must be kept uncompressed
        since it should be easy to read quickly.</p>
    <p>
        The first section, Section 0, must be present, must be uncompressed and must contain
        only the header object. This object contains information about the file as a whole,
        and is discussed in detail in <a href="#HeaderObject">Section 10.1</a>.</p>
    <p>
        If there are external references in the file, then these must all appear in a single
        section immediately following the header section. This section may be compressed
        or uncompressed. External references allow scenes to be built up from a collection
        of separate files, and are discussed in detail in <a href="#ExternalReference">Section
            10.2</a>.</p>
    <p>
        Following these are an unspecified number of sections containing scene objects.</p>
    <p>
        The file must contain the header section, plus at least one other non-empty section
        (containing at least one object). It is possible to have a file consisting solely
        of external references, or solely of scene objects.</p>
    <p>
        A file containing no objects at all is not a valid M3G file, and must be treated
        as an error.</p>
    <h2 class="SectionTitle" id="FileIdentifier">5 File Identifier</h2>
    <p>
        The file identifier is a unique set of bytes that will differentiate the file from
        other types of files. It consists of 12 bytes, as follows:</p>
    <blockquote>
        <pre>Byte[12] FileIdentifier = { 0xAB, 0x4A, 0x53, 0x52, 0x31, 0x38, 0x34, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }</pre>
    </blockquote>
    <p>
        This can also be expressed using C-style character definitions as:</p>
    <blockquote>
        <pre>Byte[12] FileIdentifier = { '&laquo;', 'J', 'S', 'R', '1', '8', '4', '&raquo;', '\r', '\n', '\x1A', '\n' }</pre>
    </blockquote>
    <p>
        The rationale behind the choice values in the identifier is based on the rationale
        for the identifier in the PNG specification. This identifier both identifies the
        file as an M3G file and provides for immediate detection of common file-transfer
        problems.</p>
    <ul>
        <li>Byte [0] is chosen as a non-ASCII value to reduce the probability that a text file
            may be misrecognized as an M3G file.</li>
        <li>Byte [0] also catches bad file transfers that clear bit 7.</li>
        <li>Bytes [1..6] identify the format, and are the ascii values for the string "JSR184".</li>
        <li>Byte [7] is for aesthetic balance with byte 1 (they are a matching pair of double-angle
            quotation marks).</li>
        <li>Bytes [8..9] form a CR-LF sequence which catches bad file transfers that alter newline
            sequences.</li>
        <li>Byte [10] is a control-Z character, which stops file display under MS-DOS, and further
            reduces the chance that a text file will be falsely recognised.</li>
        <li>Byte [11] is a final line feed, which checks for the inverse of the CR-LF translation
            problem.</li>
    </ul>
    <p>
        A decoder may further verify that the next byte is 0 (this is the first byte of
        the mandatory uncompressed header section). This will catch bad transfers that drop
        or alter zero bytes.</p>
    <h2 class="orphan" id="Section">6 Section</h2>
    <p>
        A section is a data container for one or more objects. The section header determines
        if the objects are compressed or not, how much object data there is, and also contains
        a checksum.</p>
    <p>
        In this document, we will talk about "sections that are compressed" and "sections
        that are uncompressed". In reality, we will mean "sections where the objects are
        compressed", and "sections where the objects are uncompressed".</p>
    <p>
        Each section has the following structure:</p>
    <blockquote>
        <pre>Byte                        CompressionScheme
UInt32                      TotalSectionLength
UInt32                      UncompressedLength
Byte[TotalSectionLength-13] Objects
<v2>Int32</v2>                       Checksum</pre>
    </blockquote>
    <p>
        We will now go through the individual parts of the section.</p>
    <h3 id="CompressionScheme">6.1 CompressionScheme</h3>
    <p>
        This field tells how the <tt>Objects</tt> field in this section is compressed. It
        also specifies what checksum algorithm is used. Currently, only the Adler32 checksum
        is mandatory. Compression only applies to the <tt>Object</tt> data, and not to the
        other fields in the section.</p>
    <p>
        <tt>CompressionScheme</tt> must be one of the following values:</p>
    <blockquote>
        <table border="1" cellpadding="3" cellspacing="0" class="Table">
            <tbody>
                <tr>
                    <td>
                        0</td>
                    <td>
                        Uncompressed, Adler32 Checksum</td>
                </tr>
                <tr>
                    <td>
                        1</td>
                    <td>
                        ZLib compression, 32 k buffer size, Adler32 Checksum</td>
                </tr>
                <tr>
                    <td>
                        2...255</td>
                    <td>
                        Reserved</td>
                </tr>
            </tbody>
        </table>
    </blockquote>
    <p>
        Example:</p>
    <blockquote>
        <pre>Byte CompressionScheme = 1;</pre>
    </blockquote>
    <p>
        indicates that the <tt>Objects</tt> field in the section is compressed using zlib
        with 32 k buffer size.</p>
    <p>
        The values 2...255 are reserved for future releases and are disallowed. A loader
        that follows the specification must report an error if they are found.</p>
    <h3 id="TotalSectionLength">6.2 TotalSectionLength</h3>
    <p>
        This is the total length of the section in bytes; from the start of this section
        to the start of the next section.</p>
    <p>
        Example:</p>
    <blockquote>
        <pre>UInt32 TotalSectionLength = 2056</pre>
    </blockquote>
    <p>
        indicates that this section, including the <tt>CompressionScheme</tt>, <tt>TotalSectionLength</tt>,
        <tt>UncompressedLength</tt>, <tt>Objects</tt> and <tt>Checksum</tt> fields, will
        be 2056 bytes in length.</p>
    <h3 id="UncompressedLength">6.3 UncompressedLength</h3>
    <p>
        Knowing the size of the decompressed data ahead of time can be used to make Zlib
        inflation much easier and less memory hungry. Therefore, the size of the compressed
        part of the section (in bytes) before compression (or after decompression) is serialized
        as part of the section information. Since it is only the <tt>Objects</tt> field
        that can be compressed, <tt>UncompressedLength</tt> contains the length of the <tt>Objects</tt>
        field after decompression. If no compression is specified for this section, this
        equals the actual number of bytes serialized in the <tt>Objects</tt> array.</p>
    <p>
        A value of 0 in this field is legal - the section is simply ignored. However, it
        is recommended that any process that creates a file should check for 0 length sections
        and eliminate them to reduce file size.</p>
    <p>
        Example:</p>
    <blockquote>
        <pre>UInt32 UncompressedLength = 4560</pre>
    </blockquote>
    <p>
        Means that in this section, after decompression, the <tt>Objects</tt> field is 4560
        bytes in length.</p>
    <h3 id="Objects">6.4 Objects</h3>
    <p>
        The objects in each section are serialized as an array of bytes, one after the other.
        This array of bytes will either be compressed (if CompressionScheme is 1) or it
        will be uncompressed. If it is compressed, it is compressed as a single chunk of
        data, not as separate objects. Zero bits must be padded in the end to make the <tt>Objects</tt>
        field byte aligned.</p>
    <p>
        The structure of each individual object's data is documented in <a href="#SpecialObjectData">
            Section 10</a>, <a href="#PerClassData">Section 11</a> and <a href="#PerClassData20">
                Section 12</a>.</p>
    <h3 id="Checksum">6.5 Checksum</h3>
    <p>
        To be able to verify that the section was correctly loaded, there is a 32-bit checksum
        of all the data in the section. The checksum algorithm is specified by the <tt>CompressionScheme</tt>
        field. Currently, only the Adler32 checksum is mandatory. The checksum is calculated
        using all preceding bytes in the section, i.e. the <tt>CompressionScheme</tt>, <tt>TotalSectionLength</tt>,
        <tt>UncompressedLength</tt>, and the actual serialized data in the <tt>Objects</tt>
        field (i.e. in its compressed form if compression is specified).
        If the Adler-32 algorithm is used, the <v2>unsigned</v2> checksum is
        <v2>naively converted to a signed value and then</v2> stored as a regular
        <v2>Int32</v2> in little-endian form rather than using the big-endian byte
        ordering defined by RFC 1950.</p>
    <p>
        Example:</p>
    <blockquote>
        <pre>Int32 Checksum = 0xffe806a3</pre>
    </blockquote>
    <p>
        On limited devices, we might not be able to afford to load an entire section before
        interpreting it. Thus the loader may start interpreting the objects before knowing
        that the section as a whole is correct. However, the checksums are still useful
        in that we at least know afterwards that there was an otherwise undetected error
        if the checksums differed.</p>
    <p>
        Even on a system that can afford to load an entire section before interpreting it, it
        is possible to have errors in the file. The content creation program can have a
        defect, the transmission of the file could be error-prone, or the file could have
        been altered as part of a deliberate attack on the device. Thus it is important
        that the loader tries to detect errors also in files that have correct checksums.</p>
    <p>
        The loader implementation may decide not to compute (and/or check) the checksum.
        Thus, a file with erroneous checksums is not guaranteed to be rejected. However,
        a file with erroneous checksums is not an M3G compliant file and must not pass a
        strict verification test.</p>
    <h2 class="SectionTitle" id="ObjectStructure">7 Object Structure</h2>
    <p>
        The object data stored in each section is first decompressed and then interpreted
        as a sequence of objects. This separates the act of decompression from the interpretation
        of the data. All data documented in this section is assumed already to be in its
        uncompressed form.</p>
    <p>
        Each object in the file represents one object in the scene graph tree,and is stored
        in a chunk. The structure of an object chunk is as follows:</p>
    <blockquote>
        <pre>Byte          ObjectType
UInt32        Length
Byte[Length]  Data</pre>
    </blockquote>
    <h3 id="ObjectType">7.1 ObjectType</h3>
    <p>
        This field describes what type of object has been serialized. For instance, we could
        have a Camera node, a Mesh node or a Texture2D object. <a href="#ObjectTypeValues">Section
            13</a> includes a table that shows the correspondence between ObjectType values
        and the actual object types. The ObjectType field must hold a valid value as defined
        in Section 13. The reserved object types (values 39..252) must be treated as errors.</p>
    <p>
        The values 0 and 253 to 255 are special: 0 represents the header object, and 253 to 255
        represent various types of external reference. These are detailed in <a href="#SpecialObjectData">
            Section 10</a></p>
    <p>
        Example:</p>
    <blockquote>
        <pre>Byte ObjectType = 14</pre>
    </blockquote>
    <p>
        This means that the current object is a <tt>Mesh</tt> object (see <a href="#ObjectTypeValues">
            Section 13</a>).</p>
    <h3 id="ObjectLength">7.2 Length</h3>
    <p>
        This contains the length of the Data array, in bytes. Note that a value of 0 in
        this field may be legal; some objects require no additional data over and above
        their mere presence.</p>
    <p>
        Example:</p>
    <blockquote>
        <pre>UInt32 Length = 2032</pre>
    </blockquote>
    <p>
        indicates that the <tt>Data</tt> field of this object spans 2032 bytes in the (decompressed)
        file.</p>
    <h3 id="ObjectData">7.3 Data</h3>
    <p>
        This is data that is specific for the object. It is up to the loader to interpret
        this data according to the object type and populate the object accordingly. Detailed
        information on the data for each object type is documented in <a href="#SpecialObjectData">
            Section 10</a>, <a href="#PerClassData">Section 11</a> and <a href="#PerClassData20">
                Section 12</a>.</p>
    <p>
        For instance, if the object just contained a single color, the Data would be a 3
        byte long array, where the first byte represents the red component, the second byte
        the green component, and the third byte the blue component.</p>
    <p>
        Attempts to read off the end of an object's data are disallowed and must be signalled
        as errors. An example of this would be an object with a reported length of 32 bytes,
        but which internally specifies an array with 65537 members.</p>
    <p>
        Conversely, the deserialization code for each object may also check that each byte
        of the data belongs to a valid interpretation. Additional bytes after the end of
        an object's valid data are disallowed. This condition may be difficult to determine
        on the target platform, but any file which contains "extra" data in object chunks
        is not an M3G compliant file and must not pass a strict verification test.</p>
    <p>
        <v2>Where an object's data definition has new fields for M3G 2.0, and
an M3G 1.0 file is loaded, the new fields are set to their default values,
as specified by the Object's constructor.</v2>
    </p>
    <h2 class="SectionTitle" id="ObjectOrdering">8 Object Ordering</h2>
    <p>
        All the objects in the scene graph are serialized in leaf-first order, or reference
        based order as it is also called. Before serializing a specific object, all other
        objects referenced by that object must already have been serialized,
        <v2>with a few very specific exceptions</v2>
        . Objects may refer to themselves if this is allowed by the scene data structures.</p>
    <p>
        By definition, the root of the tree will be sent last.</p>
    <p class="new">
        Note that cycles are not
        <v2>usually</v2>
        allowed in the file format.
        <v2>Where they <em>are</em> allowed in the run-time scene
graph, these references are defined in the file format using the ForwardIndex
type instead of ObjectIndex. Where possible, even ForwardIndex fields should
ideally refer to preceding objects, as it is often expensive to "fix up" a
forward reference later, when the referenced object has been created.</v2>
    </p>
    <p>
        <v2>When serializing an M3G 2.0 file, we need to be aware of cycles.
We must first create a list of all the objects that will be serialized
to the file, so that we can later determine the actual object index number
that will be assigned to a forward reference.</v2>
    </p>
    <p>
        <v2>When serializing an M3G 1.0 file, a workaround is required to remove
cycles.</v2>
        Before a scene graph containing cyclic references can be written into a file, the
        cycles must be broken. This can be done by inserting dummy target nodes as children
        of the original alignment targets. For example, if a leaf node is aligned to the
        World, an empty Group with an identity transformation is inserted as a child of
        the World, and the alignment redirected to that.</p>
    <p>
        <span class="new">Given a scene graph with no cycles, it is possible to use a "leaves
            first" strategy for output</span> - start by serializing all the objects that
        do not reference other objects, and then all the objects that refer to the objects
        already sent, and so it continues until all objects are sent.</p>
    <p>
        <v2>In order to deal with potential cycles (and as a more easily
implemented version in general), a "depth first" strategy can be used, where each
object recursively applies the following procedure, to build up a
table of references in order of serialization. (It is assumed that the
table is initially empty, and all objects are intially marked as not visited.)</v2>
    </p>
    <blockquote>
        <pre><v2>BuildReferenceTable:
if this object has not already been visited,

    mark this object as visited

    for each reference in this object,
        call BuildReferenceTable on the referred object

    append this object to the reference table.</v2></pre>
    </blockquote>
    <p>
        <v2>Each object can then be serialized from the reference table in order,
and the index of any object can be determined by searching for it in the table.
It also has the advantage that even those fields which may contain forward
references automatically generate backward references wherever possible, which
is a desirable result.</v2>
    </p>
    <p>
        For example, assume that we have the following tree structure:</p>
    <p align="center">
        <img alt="Tree with node A as root, B under A, C and D under B, E under A again, and F under E"
            height="199" src="./javax/microedition/m3g/doc-files/FileFormat-8-1.png" width="433" /></p>
    <p>
        One valid ordering of the objects is C D F B E A. This is the ordering that occurs
        if the "leaves first" method is used. Note that other leaf-first orderings are also
        valid, for instance F D C E B A.</p>
    <p>
        The "depth-first" method produces valid orderings where interior nodes in the graph
        may be sent before all the leaves have been sent. If we have a left-to-right traversal
        of children, then the depth-first method discussed above would produce the valid
        ordering C D B F E A.</p>
    <p>
        The only important thing is that any objects referenced by a particular object
        <v2>with an ObjectIndex</v2>
        are sent before the object itself.</p>
    <p>
        With this flexibility, the ordering of references can be forced by the file creator
        if this is advantageous. For example, if we wish textures to be sent in a separate
        section that is uncompressed. Thus, if we have the following tree:</p>
    <p align="center">
        <img alt="Tree with node A as root, B under A, T1 and D under B, E under A again, and T2 under E"
            height="199" src="./javax/microedition/m3g/doc-files/FileFormat-8-2.png" width="433" /></p>
    <p>
        where T1 and T2 are textures, we can send the scene graph using, for instance:</p>
    <blockquote>
        <table border="1" cellpadding="3" cellspacing="0" class="Table">
            <tbody>
                <tr>
                    <td>
                        Identifier</td>
                    <td>
                        &nbsp;</td>
                    <td>
                        File Identifier (see <a href="#FileIdentifier">Section 5</a>)</td>
                </tr>
                <tr>
                    <td>
                        Section 0</td>
                    <td>
                        Uncompressed</td>
                    <td>
                        File Header Object</td>
                </tr>
                <tr>
                    <td>
                        Section 1</td>
                    <td>
                        Uncompressed</td>
                    <td>
                        T1 T2</td>
                </tr>
                <tr>
                    <td>
                        Section 2</td>
                    <td>
                        Compressed</td>
                    <td>
                        D B E A</td>
                </tr>
            </tbody>
        </table>
    </blockquote>
    <p>
        Other orderings are also possible, for instance:</p>
    <blockquote>
        &nbsp;
        <table border="1" cellpadding="3" cellspacing="0" class="Table">
            <tbody>
                <tr>
                    <td>
                        Identifier</td>
                    <td>
                        &nbsp;</td>
                    <td>
                        File Identifier (see <a href="#FileIdentifier">Section 5</a>)</td>
                </tr>
                <tr>
                    <td>
                        Section 0</td>
                    <td>
                        Uncompressed</td>
                    <td>
                        File Header Object</td>
                </tr>
                <tr>
                    <td>
                        Section 1</td>
                    <td>
                        Uncompressed</td>
                    <td>
                        T1 T2</td>
                </tr>
                <tr>
                    <td>
                        Section 2</td>
                    <td>
                        Compressed</td>
                    <td>
                        D E B A</td>
                </tr>
            </tbody>
        </table>
    </blockquote>
    <p>
        or even (with a naive file creator):</p>
    <blockquote>
        &nbsp;
        <table border="1" cellpadding="3" cellspacing="0" class="Table">
            <tbody>
                <tr>
                    <td>
                        Identifier</td>
                    <td>
                        &nbsp;</td>
                    <td>
                        File Identifier (see <a href="#FileIdentifier">Section 5</a>)</td>
                </tr>
                <tr>
                    <td>
                        Section 0</td>
                    <td>
                        Uncompressed</td>
                    <td>
                        File Header Object</td>
                </tr>
                <tr>
                    <td>
                        Section 1</td>
                    <td>
                        Uncompressed</td>
                    <td>
                        T1</td>
                </tr>
                <tr>
                    <td>
                        Section 2</td>
                    <td>
                        Compressed</td>
                    <td>
                        D</td>
                </tr>
                <tr>
                    <td>
                        Section 3</td>
                    <td>
                        Uncompressed</td>
                    <td>
                        T2</td>
                </tr>
                <tr>
                    <td>
                        Section 4</td>
                    <td>
                        Compressed</td>
                    <td>
                        B E A</td>
                </tr>
            </tbody>
        </table>
    </blockquote>
    <p>
        Because multiple root-level objects are allowed in the file format, there is no
        obvious end point in the data. In order that the loader can determine that the file
        has ended, the total length of the file is stored in the header. Reading from the
        file is ended when the total number of bytes is reached. At this point, any objects
        not yet linked into the scene graph are treated as root-level objects and returned
        to the application.</p>
    <h3 id="ObjectReferences">8.1 Object References</h3>
    <p>
        Each object serialized, including the header object, is given an index, in order,
        starting from 1. The 0 index is used to indicate a null reference. This index is
        unrelated to the user ID for an object.</p>
    <p>
        A reference to an object is serialized as an integer containing its index within
        the file. The serialization order constraint can be expressed as follows:</p>
    <p>
        For an object with index <b>i</b>, an
        <v2>ObjectIndex referencing
another object with index</v2>
        <b>r</b> within it is only valid if <b>r</b> &lt;= <b>i</b>.
        <v2>A ForwardIndex <b>f</b> is only valid if
<b>f</b> &lt;= <b>N</b>, where <b>N</b> is the total number of
serialized objects in the file.</v2>
        Invalid indices must be treated as an error.</p>
    <p>
        An object reference must refer to an object of a valid type for the reference involved.
        For example, the reference from an Appearance object to a Material object must actually
        refer to a Material object. If the referred object type is incorrect, this must
        be treated as an error.</p>
    <h3 id="SharedObjects">8.2 Shared Objects</h3>
    <p>
        Shared objects are handled the same way as normal objects. We only need to make
        sure that a shared object is sent before both of the objects that reference it.</p>
    <p>
        For instance, for the following tree of references, where X is a shared object</p>
    <p align="center">
        <img alt="Tree with node A as root, B under A, X and D under B, E under A again, and X shared under E"
            height="199" src="./javax/microedition/m3g/doc-files/FileFormat-8-3.png" width="237" /></p>
    <p>
        A possible ordering would be D X B E A. Both the leaves-first and the depth-first
        algorithms described above will generate valid orderings.</p>
    <h3 id="CyclicReferences">8.3 Cyclic References</h3>
    <p>
        <v2>Let us now extend our example tree from before, to include
a potential forward reference (for example, an alignment constraint)
from object D to object F. This does not introduce a cycle, and
our ordering algorithm produces a valid ordering of C F D B E A,
which since there are no cycles, consists purely of backward
references. F is effectively treated as a shared object.</v2>
    </p>
    <p>
        <v2>If we now create a cycle by changing the target of this forward
reference so that it points to B, not F, then the suggested algorithm
still works. It does not change the original ordering, C D B F E A,
but D now contains a single ForwardIndex, referencing object B.</v2>
    </p>
    <h3 id="SubtreeLoading">8.4 Subtree Loading</h3>
    <p>
        With reference based order, it will be more difficult to load an arbitrary subtree
        from a file than with, e.g., root-first order. However, it is still possible, using
        two passes of the file.</p>
    <p>
        Assume that the subtree is defined as "object number X and all its children". In
        the first pass, only the node references are decoded, and an empty tree of the complete
        scene graph is created. From this graph, we find node X and make a list of all its
        descendants in the subtree. During the second pass, we simply load all the objects
        in the list. The last object that was loaded will be the root of the subtree.</p>
    <p>
        In the case where rewinding the stream is not possible, it is also possible to do
        subtree loading in just one pass. This is achieved by loading everything up until
        the root node of the desired subtree, and then letting the garbage collection remove
        everything that is not referred to by the subtree. However, such an implementation
        would consume more memory than the two-pass implementation above. In the worst case,
        this is no different from loading the entire scene. For example, if the file contains
        a 3D map of the whole world and all you want is a specific house, you may still
        need to load the entire world and then delete everything but the house, if the house
        is the last object in the file.
        <v2>Experience with M3G content development
suggests that this ability is rarely, if ever, required.</v2>
    </p>
    <h2 class="SectionTitle" id="ErrorHandling">9 Error Handling</h2>
    <p>
        There are several points at which an error may be detected. These include, but are
        not limited to:</p>
    <ul>
        <li>Memory exhaustion</li>
        <li>Missing or malformed file identifier</li>
        <li>Invalid section type</li>
        <li>Invalid file, section, or object length</li>
        <li>Invalid section checksum</li>
        <li>Invalid object type</li>
        <li>Extra or missing object data</li>
        <li>Invalid object reference</li>
        <li>Invalid enumeration value</li>
        <li>Invalid boolean value</li>
        <li>Invalid floating point value</li>
        <li>Values out of range for property</li>
        <li>Attempt to read past end of stream</li>
        <li>Aborted download</li>
        <li>Error in external reference</li>
        <li class="v2">Advanced block feature loaded into basic block implementation</li>
    </ul>
    <p>
        In particular, if values read from the loaded file would cause an <i>immediate</i>
        exception when passed to the API (e.g. all the attenuation parameters on a light
        are 0.0, or an image is too large for the implementation to handle), then this must
        be treated as an error.</p>
    <p class="v2">
        One instance of this problem that is worth highlighting is the case of a version
        2.0 file which contains advanced block features (e.g. a non-null <tt>stencil</tt>
        reference in a <tt>CompositingMode</tt> object, or a <tt>Stencil</tt> object instance).
        When this is loaded into an implementation that supports advanced block features,
        this is not a problem, but it must be treated as an error when loaded into any
        implementation that supports only the basic block.</p>
    <p>
        If combinations of values are read that may cause a <i>deferred</i> exception, (e.g.
        a material and light are both present, but there are no normals specified), then
        this must <i>not</i> be treated as an error by the Loader. The application must
        be given the opportunity to take action after loading, in order to avoid these exceptions.</p>
    <p>
        If any kind of error is detected during loading, the required action is for the
        Loader to abort this download, and that of any pending external references, clear
        up any temporary data structures, and throw an exception. If this file is being
        used as an external reference, then this is also treated as an error in the file
        that is attempting to load it. (This definition is, of course, recursive.)</p>
    <p>
        The practical upshot of this is that any error detected in any of the files that
        may make up a world being loaded must result in a safe abort of the loading process
        and the throwing of a single exception to the main application.</p>
    <p>
        It is up to the application what action, if any, is taken in the event of a loading
        error. Options range from an apologetic alert to the user ("Download failed!"),
        up through sophisticated error recovery schemes involving alternate file locations,
        or even different content in extreme cases.</p>
    <h2 class="SectionTitle" id="SpecialObjectData">10 Special Object Data</h2>
    <p>
        The data for the "special" object types is documented here.</p>
    <h3 id="Header">10.1 Header Object</h3>
    <p>
        Object Type: 00<br />
        Superclass data: <i>none</i><br />
        Followed by:</p>
    <blockquote>
        <pre>Byte[2] VersionNumber
Boolean hasExternalReferences
UInt32  TotalFileSize
UInt32  ApproximateContentSize
String  AuthoringField</pre>
    </blockquote>
    <p>
        There must be exactly one Header object in a file, and it must be the only object
        in the first section of the file, which in turn must be uncompressed. Due to its
        position in the file, it will always be assigned object index 1.</p>
    <p>
        <tt>VersionNumber</tt> is a unique version number identifying variants of the file
        fomat.
        <v2>Two variants are currently specified:</v2>
    </p>
    <table align="center" border="1" cellpadding="3" cellspacing="0" class="v2">
        <tr>
            <th>
                VersionNumber[0]</th>
            <th>
                VersionNumber[1]</th>
            <th>
                Format Version</th>
            <th>
                Used in M3G Version</th>
        </tr>
        <tr>
            <td>
                1</td>
            <td>
                0</td>
            <td>
                1.0</td>
            <td>
                M3G 1.0, 1.1, 2.0</td>
        </tr>
        <tr>
            <td>
                2</td>
            <td>
                0</td>
            <td>
                2.0</td>
            <td>
                M3G 2.0</td>
        </tr>
    </table>
    <p>
        The first number is major revision number, followed by minor revision.
        <v2>Some data definitions are dependent on the format version number. These are
indicated by comparisons against a notional variable called FILE_FORMAT, which
may be 1.0 or 2.0. In order to avoid overly repetitious use of this, those
object types which only appear in format version 2.0 are separated out into
their own section.</v2>
    </p>
    <p>
        <tt>hasExternalReferences</tt> is a boolean that describes whether this file is
        self-contained or includes URIs for other files, such as textures or geometries.
        If this is <tt>false</tt>, the file is self-contained. If it is <tt>true</tt>, then
        it indicates that the immediately following section of the file will contain the
        external reference objects needed to specify these external links. See <a href="#ExternalReference">
            Section 10.2</a> for more details.</p>
    <p>
        <tt>TotalFileSize</tt> is the total size of the file, from the start to the end.
        It will be used in the loading, so it must be correct. (That is, it is not a hint.)
        For example, a file of size 6783 would define this field as <tt>TotalFileSize = 6783</tt>.</p>
    <p>
        <tt>ApproximateContentSize</tt> contains the total number of bytes required to dowload
        the entire scene, including external links such as textures and geometry. This is
        provided as a hint, so that the user can know how much data he/she will pay for
        before loading the entire scene. The <tt>ApproximateContentSize</tt> field is also
        necessary in order to produce a good progress bar during the loading of the scene.</p>
    <p>
        It should be noted that this information is only a hint. For instance, the file
        sizes of the objects that this file is linked to might have changed. Due to this,
        it is called "approximate" content size. Note that <tt>ApproximateContentSize</tt>
        should be equal to <tt>TotalFileSize</tt> if <tt>ExternalFiles</tt> is false.</p>
    <p>
        For example, a file of 6083 bytes, with an external reference to another file of
        10700 bytes would set <tt>ApproximateContentSize = 16783</tt>.</p>
    <p>
        <tt>AuthoringField</tt> consists of a single nul-terminated UTF-8 string. The content
        of the string is not defined, and may include any information that the authoring
        environment wishes to place into it. Its most common purpose is mainly to make it
        possible to put a copyright note on the file, for example: <tt>AuthoringField = "Blast4Fun
            (C) 2003 Extreme Games Inc."</tt></p>
    <p>
        Note that if the string just contains numbers and letters from the English alphabet,
        the UTF-8 encoding will be the same as ASCII encoding.</p>
    <h3 id="ExternalReference">10.2 External Reference</h3>
    <p>
        ObjectType: 0xFF (255)<br />
        Superclass data: <i>none</i><br />
        Followed by:</p>
    <blockquote>
        <pre>String  URI</pre>
    </blockquote>
    <p>
        Instead of storing an object in-place, it is possible to have an external reference,
        in the form of a URI. This is stored in the object data as a single, nul-terminated
        UTF-8 string.</p>
    <p>
        Relative URIs are relative to the file in which they are found, as usual. For example,
        a URI of "http://www.gamesforfun.com/objs/redcar.m3g", indicates another file in
        the M3G file format, at an absolute address, and "bluecartexture.png" indicates
        a PNG file in the same location as the current file.</p>
    <p>
        If an external reference cannot be loaded, this will result in an error, causing
        the parent file to be "unloadable".</p>
    <p>
        Loops of external references (e.g. file A references file B which in turn references
        file A again) are illegal and
        <v2>must</v2>
        result in a loading error.</p>
    <p>
        The loader must only indicate that the loading of a file is complete when all external
        references within it have also been successfully loaded and the references type
        checked.</p>
    <p>
        External references may appear only within their own section within the file. If
        present, this appears immediately after the file header section. It may be compressed
        or uncompressed.</p>
    <p>
        In order to facilitate type checking of external references, loading of the externally
        referenced file must complete before reading any objects which could refer to it.
        This is one of the main reasons for ensuring that external references are in their
        own section, which occurs before sections containing objects of other types.</p>
    <p>
        For example, if the external reference is referred to as if it were an Appearance
        object, then the check that it is indeed an Appearance can occur only after loading
        the referred file.</p>
    <p>
        External reference loading must support
        <v2>all required</v2>
        file types in order to satisfy the specification. An external reference to any other
        type of file must be treated as an error. To stress the point, even if a particular
        format (e.g., TIFF) is otherwise supported by the Loader, it must still reject any
        M3G files that reference TIFF images.</p>
    <p>
        For M3G format files, the external reference must be able to load another M3G format
        file containing a single root-level object. If more than one root-level object is
        defined, then the first root-level object will be used, and the other objects and
        their descendants discarded.
        <v2>There is no restriction on references to different
file format types - a version 2.0 file may reference a version
1.0 file or vice versa.</v2>
    </p>
    <p>
        For PNG<v2>, JPEG or KTX</v2>
        format files, the external reference must be able to reference a valid PNG<v2>, JPEG or KTX</v2>
        file, in which case the object created is a single instance of Image2D.</p>
    <p>
        In all cases, once loading completes, the single root-level object loaded from the
        file effectively replaces the external reference object in the object index table.
        References to that index will then nominate the root-level object.</p>
    
    <h3 class="v2" id="ExternalReferenceImage">
        10.3 External Image Reference</h3>
    <p class="v2">
        ObjectType: 0xFE (254)<br />
        Superclass data: <a href="#ExternalReference">External Reference</a><br />
        Followed by:</p>
    <blockquote class="v2">
        <pre>Int32         format;</pre>
    </blockquote>
    <p class="v2">
        This external reference must refer to a valid PNG, JPEG or KTX file, and the image created
        is a single instance of Image2D. The difference from the default behavior of the base class
        is that a destination format is also supplied for the image. This allows content creators
        to easily use images in more flexible ways.
    </p>
    <p class="v2">
        For example, if included using the basic variant of external reference, a greyscale image
        is interpreted as a luminance-only format . With this external image reference, it is 
        possible to specify that the image data should instead be treated as alpha instead,
        or expanded to luminance-alpha, or even RGBA. The NO_MIPMAPS flag is also respected.
    </p>
    <p class="v2">
        Conversions are handled according to the <a href="index.html#PixelFormats">general rules</a>
        on pixel format conversions as shown in the package description.
    </p>
    <p class="v2">
        The <tt>format</tt> field must hold a valid <a href="javax/microedition/m3g/Image2D.html#field_summary">
        enumerated value</a>, as specified in the Image2D class definition. Other values must
        be treated as errors.
    </p>

    <h3 id="ExternalReferenceObject" class="v2">
        10.4 External Object Reference</h3>
    <p class="v2">
        ObjectType: 0xFD (253)<br />
        Superclass data: <a href="#ExternalReference">External Reference</a><br />
        Followed by:</p>
    <blockquote class="v2">
        <pre>Int32[]       userID;</pre>
    </blockquote>
    <p class="v2">
        It is often useful to reference several objects within a single file, rather than
        just the root object. This object looks inside the file nominated by the external
        reference, and finds (using the same rules as the Object3D.find method) an object
        within it that has the nominated user ID. The find method is called for each root
        object in the file in turn.
    </p>
    <p class="v2">
        If an array of objects has also been passed into the <tt>Loader.load</tt> method,
		then this array may be searched instead by specifying an empty string as the URL.
		Lookup proceeds as before, only this time it searches the objects in the supplied
		array, instead of the array of root objects in the file. If one of the variants
		of <tt>Loader.load</tt> has been used where there is no object array passed in, 
		then the search will fail and this will be treated as an error.
    </p>
    <p class="v2">
		The <tt>userID</tt> array must contain at least one element.
		If any of the <tt>userID</tt>s is not found, then this must be treated as an error.
		If multiple objects with the same <tt>userID</tt> are reachable from the root
		object array, then (as with find) any one of them may be returned. We recommend
		that content developers take care to avoid this case, by ensuring that files
		do not contain duplicate user IDs.
    </p>
    <p class="v2">
        This object is special in that it may create multiple object indices, in order that
        other objects can reference each of the objects nominated inside the <tt>userID</tt> array.
        Object 0 of the array will be referenced using the "natural" object index of the
        XREF object itself, and subsequent objects will be assigned sequential indices.
    </p>
    <p class="v2">
        There are two different use cases which must be catered for. To
        illustrate, imagine that we have a file called "cars.m3g", which
        contains two cars (with user IDs 1111 and 2222), and they are the
        same color so they share an appearance.
    </p>
    <p class="v2">
        The first use case is where we wish to share the appearance between the
        cars so that changes to it propagate to both. In this case, we have a
        single external object reference object, with an inherited URI of
        "car.m3g". This contains an array of two userIDs, one with user ID 1111
        and the other with user ID 2222. Only a single file is loaded, and thus
        there is only one instance of the appearance.
    </p>
    <p class="v2">
        The second is where we wish to get a copy of an object within the file.
        In the car example, we may not want to share the appearance, so that
        changes to it are separately specified on each car. In this case, we
        have two external object references to "car.m3g", each of which has a
        single userID. This loads "car.m3g" twice, instantiating two complete
        copies of everything, including the appearance. The unreferenced cars
        from each load are removed as usual for unreferenced root objects.
    </p>
    <p class="v2">
        The usual rules for scene construction apply. Types must match, and any
        other constraints must be satisifed as if the contents of the external
        file had been included inline. You may not, for example, use a node
        inside the file as a child of another node, if it already has a parent
        node.
    </p>
    <p class="v2">
        Here is the structure of an example file, illustrating the use of
        multiple userIDs:
    </p>
    <pre class="v2">        Header Section

            #1 Header object

        XREF Section

            #2 XREF 
                URI: "/res/some-image.png"

            #3 ObjectXREF
                URI: "/res/cars.m3g"
                UserID Count: 2
                UserID: 1111
                UserID: 2222	// Becomes object index #4

        Object Section

            #5 Texture
                Image2D: #2

            #6 Group
                Child: #3

            #7 Group
                Child: #4</pre>
    <p class="v2">
        For comparison, object #2 is a normal XREF, which is effectively
        replaced by the Image2D object that is created by loading the file.
        Object #5 references it.
    </p>
    <p class="v2">
        Object #3 is an Object XREF, which loads file "/res/cars.m3g", and looks
        up the object with UserID 1111. This effectively becomes object #3. But,
        since it contains multiple UserIDs, it also looks up UserID 2222,
        becoming object #4. This is special behaviour, in that it is the only
        place where a single object in the file becomes more than one object in
        the scene.
    </p>
    <p class="v2">
        To illustrate the flexibility to instance or copy objects, consider:
    </p>
    <pre class="v2">        #2 ObjectXREF
            URI: "/res/appearances.m3g"
            UserID Count: 2
            UserID: 3333
            UserID: 3333	// Second reference becomes object index #3</pre>
    <p class="v2">
        Versus
    </p>
    <pre class="v2">        #2 ObjectXREF
            URI: "/res/appearances.m3g"
            UserID Count: 1
            UserID: 3333

        #3 ObjectXREF
            URI: "/res/appearances.m3g"
            UserID Count: 1
            UserID: 3333</pre>
    <p class="v2">
        In the first case, objects #2 and #3 are both actually references to a
        single shared appearance object. In the second case, two copies of the
        world are loaded and therefore objects #2 and #3 are separate copies of
        the appearance, albeit identical to start with.
    </p>
    <h2 class="SectionTitle" id="PerClassData">11 Per-Class Data
        <v2>for Format 1.0</v2>
    </h2>
    <p>
        The data for each class in the API is now presented in alphabetical order.
        <v2>In order to avoid a large number of statements of the form
"IF FILE_FORMAT == 2.0", classes which appear only in the 2.0 version
of the file format are presented separately in <a href="#PerClassData20">Section 12</a>.</v2>
        Where a class is a subclass, the superclass's data is always output first, and this
        information is taken to be part of the data for the class as a whole.</p>
    <p>
        Classes without a serialized form (e.g. Graphics3D) are shown here for completeness,
        but are indicated as "not a serializable class".</p>
    <p>
        Detailed information about each field is not given - it should be assumed that the
        data have the same meanings as those assigned in the API. Where data is serialized
        in a form which is different from the way it is specified in the API, this alternate
        form is documented here.</p>
    <p>
        Any values which would be invalid as arguments to the corresponding methods in the
        API are also invalid in the file and must be reported as errors. For example, a
        negative value in the light attenuation fields is disallowed by the API and is therefore
        also disallowed in the file format.</p>
    <h3 id="AnimationController">11.1 AnimationController</h3>
    <p>
        ObjectType: 01
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre>Float32       speed;
Float32       weight;
Int32         activeIntervalStart;
Int32         activeIntervalEnd;
Float32       referenceSequenceTime;
Int32         referenceWorldTime;</pre>
    </blockquote>
    <h3 id="AnimationTrack">11.2 AnimationTrack</h3>
    <p>
        ObjectType: 02
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre>ObjectIndex   keyframeSequence;
ObjectIndex   animationController;
<v2>
<i>IF FILE_FORMAT == 2.0, THEN</i>

    UInt16        propertyID;
    
    <i>IF propertyID >= FLOAT && propertyID <= SAMPLER_CUBE, THEN</i>
    
        Boolean       isNormalizeEnabled;
        
    <i>END</i>
    
<i>ELSE</i></v2>   

    UInt32        propertyID;

<i class="v2">END</i></pre>
    </blockquote>
    <p>
        The <tt>propertyID</tt> field must hold <v2>either</v2> a valid <a href="javax/microedition/m3g/AnimationTrack.html#field_summary">
        enumerated <v2>property ID</v2> value</a>, as specified in the class definition<v2>, or a valid <a href="javax/microedition/m3g/ShaderVariable.html#field_summary">
        enumerated uniform type value</a>, as specified in the <tt>ShaderVariable</tt> class definition.</v2>. Other values must be treated as errors.
        <v2>For file format version 2, we notice that the property and type IDs will actually fit into a 16 bit value
        and therefore can be stored with less space than the version 1 format.</v2>
    </p>
    <p class="v2">
        If the <tt>propertyID</tt> value is a valid uniform type, then additional fields are serialized.
    </p>

<h3 id="Appearance">11.3 Appearance</h3>
    <p>
        ObjectType: 03
        <br />
        Superclass data: <a href="#AppearanceBase">AppearanceBase</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre>ObjectIndex   fog;

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>

    ObjectIndex   pointSpriteMode;
    
<i>ELSE</i></v2>

    ObjectIndex   polygonMode;
    
<i class="v2">END</i>

ObjectIndex   material;
ObjectIndex[] textures;</pre>
    </blockquote>
    <p>These are simply references to each of the objects aggregated together to form an
    appearance.</p>
    <p>
        There are as many texture objects in the textures array as there are active texture
        units for this appearance. The texture units are loaded sequentially from unit 0.
        If the implementation supports more texture units than are specified, these are
        left in their default, inactive state, with a null texture.
    </p>
    <p>
        If more textures are specified than are supported by the implementation, then this
        must be treated as an error, as it would be in the API. The application can then
        decide on an appropriate course of action to handle this case.
    </p>
    <p class="v2">
        The file format already defined for Appearance in file format version 1.0 complicates
        the treatment of the <tt>polygonMode</tt> field. In format 2.0, it is included with
        the base class data, but for format 1.0, it must be serialized with the Appearance
        data for compatibility reasons. See also <a href="#AppearanceBase">AppearanceBase</a></p>
    <h3 id="Background">11.4 Background</h3>
    <p>
        ObjectType: 04
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre>ColorRGBA     backgroundColor;
ObjectIndex   backgroundImage;
Byte          backgroundImageModeX;
Byte          backgroundImageModeY;
Int32         cropX;
Int32         cropY;
Int32         cropWidth;
Int32         cropHeight;

Boolean       depthClearEnabled;

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>
    
    Float32       depth;
    Int32         stencil;
    Int32         stencilClearmask;
    ColorRGBA     colorClearMask;

<i>ELSE</i>

    Boolean       colorClearEnabled;

<i>END</i></v2></pre>
    </blockquote>
    <p>The <tt>backgroundImageModeX</tt> and <tt>backgroundImageModeY</tt> fields must
    each hold a valid <a href="javax/microedition/m3g/Background.html#field_summary">enumerated
        value</a>, as specified in the class definition. Other values must be treated
    as errors.</p>
    <p class="v2">
        The <tt>colorClearEnabled</tt> field in the M3G 1.0 file
        format maps on to the <tt>colorWriteMask</tt> field such that
        if  <tt>colorClearEnabled</tt> is <tt>true</tt>, then the value of
        <tt>colorWriteMask</tt> is set to 0xFFFFFFFF, otherwise zero.</p>
    <p class="v2">
        If an M3G 2.0 file is loaded into a basic block implementation, then the
        <tt>stencil</tt> field must be <tt>0</tt> (i.e. a null reference), and 
        the <tt>stencilClearmask</tt> field is ignored.</p>
    <h3 id="Camera">11.5 Camera</h3>
    <p>
        ObjectType: 05
        <br />
        Superclass data: <a href="#Node">Node</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre>Byte          projectionType;

<i>IF projectionType == GENERIC, THEN</i>

    Matrix        projectionMatrix;
    
<v2><i>ELSE IF FILE_FORMAT == 2.0 AND projectionType == SCREEN, THEN</i>

    Float32       x;
    Float32       y;
    Float32       width;
    Float32       height;</v2>
    
<i>ELSE</i>

    Float32       fovy;
    Float32       AspectRatio;
    Float32       near;
    Float32       far;
    
<i>END</i></pre>
    </blockquote>
    <p>The <tt>projectionType</tt> field must hold a valid <a href="javax/microedition/m3g/Camera.html#field_summary">
        enumerated value</a>, as specified in the class definition. Other values must
        be treated as errors.</p>
    <h3 id="CompositingMode">11.6 CompositingMode</h3>
    <p>
        ObjectType: 06
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre>Boolean       depthTestEnabled;
Boolean       depthWriteEnabled;

<v2><i>IF FILE_FORMAT == 1.0, THEN</i></v2>

    Boolean       colorWriteEnabled;
    Boolean       alphaWriteEnabled;

<v2><i>END</i></v2>

Byte          blending;
Byte          alphaThreshold;
Float32       depthOffsetFactor;
Float32       depthOffsetUnits;

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>
    
    UInt16        depthTest;
    UInt16        alphaTest;
    
    ObjectIndex   blender;
    ObjectIndex   stencil;
    
    ColorRGBA     colorWriteMask;

<i>END</i></v2></pre>
    </blockquote>
    <p>The <tt>blending</tt><v2>, <tt>depthTest</tt> and
        <tt>alphaTest</tt> fields must each</v2> hold a valid <a
        href="javax/microedition/m3g/CompositingMode.html#field_summary">
        enumerated value</a>, as specified in the class
        definition. Other values must be treated as errors.</p>
    <p>
        The <tt>alphaThreshold</tt> field is stored as a byte to save space. It is mapped
        so that 0x00 is equivalent to 0.0 (completely transparent), and 0xFF is equivalent
        to 1.0 (completely opaque).</p>
    <p class="v2">
        The <tt>colorWriteEnabled</tt> and <tt>alphaWriteEnabled</tt> fields in the M3G 1.0 file
        format map on to the  alpha and RGB channels of the <tt>colorWriteMask</tt> field. If 
        <tt>colorWriteEnabled</tt> is <tt>true</tt>, then the red, green and blue bitfields in
        <tt>colorWriteMask</tt> are set to 0xFF, otherwise 0x00. If <tt>alphaWriteMask</tt> is
        <tt>true</tt>, then the alpha bitfield in <tt>colorWriteMask</tt> is set to 0xFF, 
        otherwise 0x00.</p>
    <p class="v2">
        A implementation that only implements the basic block will not include the
        <tt>blender</tt> and <tt>stencil</tt> fields. In this case, any value other
        than <tt>NULL</tt> in these fields must be treated as an error.</p>
    <h3 id="Fog">11.7 Fog</h3>
    <p>
        ObjectType: 07
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre>ColorRGB      color;
Byte          mode;

<i>IF mode == EXPONENTIAL <v2>OR (FILE_FORMAT == 2.0 AND mode == EXPONENTIAL_SQUARED)</v2>, THEN</i>
    
    Float32       density;
    
<i>ELSE IF mode == LINEAR, THEN</i>

    Float32       near;
    Float32       far;
    
<i>END</i></pre>
    </blockquote>
    <p>The <tt>mode</tt> field must hold a valid <a href="javax/microedition/m3g/Fog.html#field_summary">
        enumerated value</a>, as specified in the class definition. Other values must
    be treated as errors.</p>
    <h3 id="Graphics3D">11.8 Graphics3D</h3>
    <p><i>Not a serializable class.</i></p>
    
    <h3 id="Group">11.9 Group</h3>
    <p>
        ObjectType: 09
        <br />
        Superclass data: <a href="#Node">Node</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre>ObjectIndex[] children;
        
<v2><i>IF FILE_FORMAT == 2.0, THEN</i>
    
    Boolean       isLodEnabled;
    Float         hysteresis;
    Float         offset;
    
<i>END</i></v2></pre>
    </blockquote>
    <p class="v2">
        Note that the LOD fields are always serialized, even if LOD is disabled.</p>
    <h3 id="Image2D">11.10 Image2D</h3>
    <p>
        ObjectType: 10
        <br />
        <v2>Superclass data: <a href="#ImageBase">ImageBase</a></v2>
        <br />
        Followed By:</p>
    <blockquote>
        <pre><i>IF isMutable == false, THEN</i>
  
    Byte[]        palette;
    Byte[]        basePixels;
   
    <v2><i>IF FILE_FORMAT == 2.0, THEN</i>
    
        Byte          mipmapCount;
        
        <i>FOR each specified mipmap level...</i>
        
            Byte[]        mipmapPixels;
        
        <i>END</i>        
    
    <i>END</i></v2>
    
<i>END</i></pre>
    </blockquote>
    <p class="v2">
        The base class has changed for file format version 2.0, but this simply involves
        the movement of the data definitions. When dealing with a version 1.0 file, the
        actual data serialized by this class is exactly the same as the M3G 1.1 specification.</p>
    <p>
        For a palettised format, the <tt>basePixels</tt> array contains a single palette
        index per pixel, and the <tt>palette</tt> array will contain up to 256 entries,
        each consisting of a pixel specifier appropriate to the format chosen.
    </p>
    <p>
        For a non-palettised format, the <tt>palette</tt> array will be empty, and the <tt>basePixels</tt>
        array contains a pixel specifier appropriate to the format chosen.
    </p>
    <p>
        In a pixel specifier, each byte is scaled such that 0 represents the value 0.0 and
        255 represents the value 1.0.  <v2>5-bit and 6-bit color values are similarly scaled.</v2>
        The different formats require different data to be serialized, as follows:
    </p>
    <ul>
        <li><tt>ALPHA</tt>: a single byte per pixel, representing pixel opacity.</li>
        <li><tt>LUMINANCE</tt>: a single byte per pixel, representing pixel luminance.</li>
        <li><tt>LUMINANCE_ALPHA</tt>: two bytes per pixel. The first represents luminance, the second
            alpha.</li>
        <li><tt>RGB</tt>: three bytes per pixel, representing red, green and blue respectively.</li>
        <li><tt>RGBA</tt>: four bytes per pixel, representing red, green, blue and alpha respectively.</li>
        <li class="v2"><tt>RGB565</tt>: two bytes per pixel, the five least significant bits representing blue.</li>
		<li class="v2"><tt>RGBA5551</tt>: two bytes per pixel, the least significant bit representing alpha.</li>
		<li class="v2"><tt>RGBA4444</tt>: two bytes per pixel, the four least significant bits representing alpha.</li>
        <li class="v2"><tt>RGB_ETC</tt>: 8 bytes per 16-pixel block, as defined in the <a href="http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt">OpenGL ES ETC1 compressed texture extension</a> specification.</li>
    </ul>
    <p>The meaning of the components is given in the documentation for
        the <a href="javax/microedition/m3g/ImageBase.html"> ImageBase</a> class.</p>
    <p class="v2">
        If <tt>mipmapCount</tt> is 0, then no explicit MIPmap data is supplied. This does
        not, however, mean that no MIPmaps are generated. This is controlled by the presence
        or absence of the <tt>NO_MIPMAPS</tt> flag value in the base class. 
        must not be supplied for an image where the <tt>NO_MIPMAPS</tt> flag is active.
        A MIPmap-enabled image which relies solely on autogeneration of the MIPmaps
        can have 0 explicit MIPmaps in the file.</p>
    <p class="v2">
        MIPmap levels may be specified explicitly in the file.
        When explicit MIPmap levels are defined, the <tt>mipmapCount</tt> field must
        be equal to the number of levels in a full MIPmap pyramid. While, technically,
        this is redundant information, it may considerably simplify some implementations.
        Explicit MIPmaps must all be present, and be serialized in order of increasing
        level (i.e. larger ones come before smaller). The number of pixels in the
        <tt>mipmapPixels</tt> array is defined according to the rules in the class
        definition. The pixel format is the same as the base-level pixel data.</p>
    <p class="v2">
        For an <tt>RGB_ETC</tt> or palettised image, either <tt>noMipmaps</tt> must be
        <tt>true</tt>, or all mipmaps must be present.  For a palettised image, all mipmaps
        share the same palette.</p>

    <p class="v2">
        For a palettised image, either <tt>mipmapCount</tt> must be <tt>0</tt> and the
        <tt>NO_MIPMAPS</tt> flag must be active, or all MIPmap levels must be present
        and the <tt>NO_MIPMAPS</tt> flag must be <em>in</em>active. 
        If present, all MIPmaps share the same palette.
        </p>
    <h3 id="IndexBuffer">11.11 IndexBuffer</h3>
    <p>
        ObjectType: <i>27 (NOTE: this is an abstract base class in file format 1.0)</i>
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed by:</p>
        
    <blockquote>
        <pre>Byte       encoding;

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>
    
    Boolean       isImmutable;

    Byte          primitiveType;
    Byte          stripEncoding;
    
    <i>IF stripEncoding == 0 or 128, THEN</i>
        
        UInt32        primitiveCount;
        
        <i>IF stripEncoding == 128, THEN</i>
           
            UInt32[primitiveCount] stripLengths;
        
        <i>END</i>

    <i>ELSE IF stripEncoding == 1 or 129, THEN</i>
    
        Byte          primitiveCount;

        <i>IF stripEncoding == 129, THEN</i>

            Byte[primitiveCount]   stripLengths;
        
        <i>END</i>

    <i>ELSE IF stripEncoding == 2 or 130, THEN</i>
    
        UInt16        primitiveCount;

        <i>IF stripEncoding == 130, THEN</i>

            UInt16[primitiveCount] stripLengths;
        
        <i>END</i>
        
    <i>END</i>
    
<i>END</i></v2>
  
<i>IF encoding == 0, THEN</i>

    UInt32        startIndex;
    
<i>ELSE IF encoding == 1, THEN</i>

    Byte          startIndex;
    
<i>ELSE IF encoding == 2, THEN</i>

    UInt16        startIndex;

<i>ELSE IF encoding == 128, THEN</i>

    UInt32[]      indices;
    
<i>ELSE IF encoding == 129, THEN</i>

    Byte[]        indices;
    
<i>ELSE IF encoding == 130, THEN</i>

    UInt16[]      indices;
    
<span class="v2"><i>ELSE IF FILE_FORMAT == 2.0, THEN</i>
    
    <i>IF encoding == 192, THEN</i>
    
        Int32[]   indexDeltas; 
    
    <i>ELSE IF encoding == 193, THEN</i>
    
        Byte[]    indexDeltas;
        
    <i>ELSE IF encoding == 194, THEN</i>
   
        Int16[]   indexDeltas;
    
    <i>END</i></span>

<i>END</i></pre>
    </blockquote>
        <p class="v2">
            The <tt>encoding</tt> field indicates the encoding scheme to be used for the indices.
            Only the nominated values are allowed. Other values must be treated as errors.</p>
        <ul class="v2">
            <li>Bit 7 of the <tt>encoding</tt> field is equivalent to the <tt>explicit</tt> property
                on the index buffer, and must be 1 if the index buffer was constructed with explicit
                indices, or 0 if constructed with implicit indices.</li>
            <li>The two low-order bits indicate the width of each index field. 0 indicates that
                32-bit integers are written, 1 indicates that a single byte will suffice, and 2
                indicates that a 16-bit integer is sufficient to hold all the given index values.</li>
            <li>Version 2.0 of the file format supports an additional flag. In case of explicit
                indices, bit 6 of the <tt>encoding</tt> field indicates whether the indices are
                stored as raw values (0) or as differences from the previous value (1). When stored
                as deltas, decoding proceeds by first initializing an accumulator to 0, and then
                adding each value to the accumulator. In order that the deltas can be represented
                within the same number of bits as the raw values, the accumulators should be the
                same length as the values required (i.e. 8, 16 or 32 bits) and be allowed to overflow.
                This also means that the accumulation is not dependent on the signed or unsigned
                nature of the deltas. (For example, the 8-bit sequence 0, 127, 126 can equally well
                be represented using deltas of 0, 127, -1 or 0, 127, 255.) This bit must not be
                set in version 1.0 files.</li>
        </ul>
    <p class="v2">
        Similarly, the <tt>stripEncoding</tt> field indicates the encoding scheme to be used for the
        primitive count, and, where present, strip lengths.
        Only the nominated values are allowed. Other values must be treated as errors.</p>
    <ul class="v2">
        <li>Bit 7 of the <tt>stripEncoding</tt> field must be 1 if the index buffer was constructed
            with strips of primitives, or 0 if constructed with arrays of primitives.</li>
        <li>The two low-order bits indicate the width of the <tt>primitiveCount</tt> and
            <tt>stripLengths</tt> fields. 0 indicates that
            32-bit integers are written, 1 indicates that a single byte will suffice, and 2
            indicates that a 16-bit integer is sufficient to hold all the given index values.</li>
    </ul>
    <p class="v2">
            Note that the <tt>encoding</tt> and <tt>stripEncoding</tt> fields are independent of one
            another. It is common, for example, to have an index buffer that uses more than 256
            indices, but has fewer than 256 strips. Setting the strip and index encoding fields
            separately in this case reduces file size.</p>
    <p class="v2">
            The <tt>primitiveType</tt> field must hold a valid
            <a href="javax/microedition/m3g/IndexBuffer.html#field_summary">enumerated value</a>,
            as specified in the class definition. Other values must be treated as errors.</p>
    <p class="v2">
            If <tt>primitiveType</tt> field has the value <tt>POINT_SPRITES</tt>, then <tt>stripEncoding</tt>
            must have bit 7 set to 0, as point sprite strips do not exist (unlike triangle strips or
            line strips).</p>
    <p class="v2">
        If the <tt>isImmutable</tt> flag is <tt>true</tt>, then the required effect is equivalent
        to calling <tt>commit</tt> on the object after loading is complete.</p>
    <h3 id="KeyframeSequence">11.12 KeyframeSequence</h3>
        <p>
            ObjectType: 19
            <br />
            Superclass data: <a href="#Object3D">Object3D</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>Byte          interpolation;
Byte          repeatMode;
Byte          encoding;
UInt32        duration;
UInt32        validRangeFirst;
UInt32        validRangeLast;

UInt32        componentCount;
UInt32        keyframeCount;

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>

    UInt32        channelCount;
    
<i>END</i></v2>

<i>IF encoding == 0</i>

    <i>FOR each key frame...</i>

        <span class="new">UInt32</span>                  time;
        Float32[componentCount<v2>*channelCount</v2>] vectorValue;
    
    <i>END</i>
    
<i>ELSE IF encoding == 1</i>

    Float32[componentCount] vectorBias;
    Float32[componentCount] vectorScale;

    <i>FOR each key frame...</i>

        <span class="new">UInt32</span>               time;
        Byte[componentCount<v2>*channelCount</v2>] vectorValue;
    
    <i>END</i>
    
<i>ELSE IF encoding == 2</i>

    Float32[componentCount] vectorBias;
    Float32[componentCount] vectorScale;
    
    <i>FOR each key frame...</i>
    
        <span class="new">UInt32</span>                 time;
        UInt16[componentCount<v2>*channelCount</v2>] vectorValue;
    
    <i>END</i>

<i>END</i>

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>

    UInt32        eventCount;
    
    <i>FOR each event...</i>

        UInt32               eventTime;
        Int32                eventID;
    
    <i>END</i>

<i>END</i></v2></pre>
        </blockquote>
        <p>
            The <tt>interpolation</tt> and <tt>repeatMode</tt> fields must each hold a valid
            <a href="javax/microedition/m3g/KeyframeSequence.html#field_summary">enumerated value</a>,
            as specified in the class definition. Other values must be treated as errors.</p>
        <p>
            All of the <tt>vectorValue</tt> arrays are the same size, so a separate count is
            stored outside the individual keyframe's data rather than with each array.</p>
        <p class="v2">
            In a version 1.0 file, the value of the <tt>channelCount</tt> field is treated as
            if it was 1 when calculating the size of the value arrays. The data for each channel
            is serialized into the arrays in channel-major order, so all the data for channel 0
            appears first, then the data for channel 1, and so on.</p>
        <p>
            The <tt>encoding</tt> field indicates the encoding scheme to be used for the keyframe
            data. Only the nominated values above are allowed. Other values must be treated
            as errors.</p>
        <ul>
            <li>Encoding 0 indicates that the values are stored "raw" as floats.</li>
            <li>Encodings 1 and 2 indicate that the values are quantized to 1 or 2 bytes. For each
                component, a bias and scale are calculated from the sequence of values for that
                component. The bias is the mimimum value, the scale is the maximum value minus the
                minimum value. The raw values are then converted to a value 0..1 by subtracting
                the bias and dividing by the scale. These raw values are then quantized into the
                range of a Byte or UInt16 by multiplying by 255 or 65535 respectively. The converse
                operation restores the original value from the quantized values.</li>
        </ul>
    <p class="v2">
        When present, the event list must be serialized in order of increasing event time.
        If two or more events have the same time, it is recommended (but not required) to further
        sort them in order of increasing event ID.</p>
    <h3 id="Light">11.13 Light</h3>
        <p>
            ObjectType: 12
            <br />
            Superclass data: <a href="#Node">Node</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>Float32       attenuationConstant;
Float32       attenuationLinear;
Float32       attenuationQuadratic;
ColorRGB      color;
Byte          mode;
Float32       intensity;
Float32       spotAngle;
Float32       spotExponent;</pre>
        </blockquote>
        <p>The <tt>mode</tt> field must hold a valid <a href="javax/microedition/m3g/Light.html#field_summary">
            enumerated value</a>, as specified in the class definition. Other values must
        be treated as errors.</p>
        <h3 id="Loader">11.14 Loader</h3>
        <p><i>Not a serializable class.</i></p>
        
        <h3 id="Material">11.15 Material</h3>
        <p>
            ObjectType: 13
            <br />
            Superclass data: <a href="#Object3D">Object3D</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>ColorRGB      ambientColor;
ColorRGBA     diffuseColor;
ColorRGB      emissiveColor;
ColorRGB      specularColor;
Float32       shininess;
Boolean       vertexColorTrackingEnabled;</pre>
        </blockquote>
        <h3 id="Mesh">11.16 Mesh</h3>
        <p>
            ObjectType: 14
            <br />
            Superclass data: <a href="#Node">Node</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>ObjectIndex   vertexBuffer;

UInt32        submeshCount;

<i>FOR each submesh...</i>

    ObjectIndex   indexBuffer;
    ObjectIndex   appearance;

<i>END</i>

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>

    UInt32        morphTargetCount;

    <i>FOR each target buffer...</i>

        ObjectIndex   morphTarget;
        Float32       initialWeight;

    <i>END</i>
    
    UInt16[]      morphSubset;
    
<i>END</i></v2></pre>

        </blockquote>
        <h3 id="MorphingMesh">11.17 MorphingMesh</h3>
        <p>
            ObjectType: 15
            <br />
            Superclass data: <a href="#Mesh">Mesh</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre><v2><i>IF FILE_FORMAT == 1.0, THEN</i></v2>

    UInt32        morphTargetCount;

    <i>FOR each target buffer...</i>
 
        ObjectIndex   morphTarget;
        Float32       initialWeight;
    
    <i>END</i>
    
<v2><i>END</i></v2></pre>
        </blockquote>
        <p class="v2">Note that the morphing information has been moved up to the base class
        for M3G Version 2.0, and this class is thus deprecated for M3G2 serialization. We recommend
        that it is not used when serializing out M3G 2.0 files, and that the information is
        included in a Mesh object instead.</p>
        
        <h3 id="Node">11.18 Node</h3>
        <p>
            ObjectType: <i>none (abstract base class)</i>
            <br />
            Superclass data: <a href="#Transformable">Transformable</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>Boolean       enableRendering;
Boolean       enablePicking;
Byte          alphaFactor;
Int32         scope;

Boolean       hasAlignment;

<i>IF hasAlignment == TRUE, THEN</i>

    Byte          zTarget;
    Byte          yTarget;
      
    <v2>ForwardIndex</v2>  zReference;
    <v2>ForwardIndex</v2>  yReference;

<i>END</i>

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>

    Boolean       hasBoundingBox;
    
    <i>IF hasBoundingBox, THEN</i>
    
        Float32       boundMinX;
        Float32       boundMaxX;
        Float32       boundMinY;
        Float32       boundMaxY;
        Float32       boundMinZ;
        Float32       boundMaxZ;
    
    <i>END</i>

    Boolean       hasBoundingSphere;
    
    <i>IF hasBoundingSphere, THEN</i>
    
        Float32       boundCenterX;
        Float32       boundCenterY;
        Float32       boundCenterZ;
        Float32       boundRadius;
    
    <i>END</i>
    
    Boolean       collisionEnabled;
    Boolean       hasCollisionShape;
    
    <i>IF hasCollisionShape, THEN</i>
        
        Int32         orientations;
        Float32[size] min;
        Float32[size] max;
    
    <i>END</i>
        
    Float32       LODResolution;
    
<i>END</i></v2></pre>
        </blockquote>
        <p>The <tt>zTarget</tt> and <tt>yTarget</tt> fields must each hold a valid <a href="javax/microedition/m3g/Node.html#field_summary">
            enumerated value</a>, as specified in the class definition. Other values must
        be treated as errors.</p>
        <p>
            The <tt>alphaFactor</tt> field is stored as a byte to save space. It is mapped so
            that 0x00 is equivalent to 0.0 (fully transparent), and 255 is equivalent to 1.0
            (fully opaque).
        </p>
        <p>
            If the <tt>hasAlignment</tt> field is <tt>false</tt>, the omitted fields are initialized
            to their default values.
        </p>
        <p class="v2">The bounding volumes are only output if they have any non-0 data.
        This is to save space, and if absent the data defaults to all 0. Since the bounds are
        calculated as the intersection of a sphere and box, this should result in no loss
        of information.</p>
        <p class="v2">The collision shape data is only output if it is present. This is to save
        space. The <tt>orientations</tt>, <tt>min</tt> and <tt>max</tt> fields are defined in
        the same way as the correspondingly named parameters of the
        <a href="javax/microedition/m3g/Node.html#setCollisionShape(int, float[], float[])">setCollisionShape</a> method.</p>
        <p class="v2">
        The size of the <tt>min</tt> and <tt>max</tt> arrays is not serialized directly, rather it is
        one more than the bit number of the highest bit set in <tt>orientations</tt>. For example, if
        <tt>orientations</tt> has the value 0x1F (i.e. it is a 10-DOP), then <tt>size</tt> is defined
        as 5 because the highest bit set is bit number 4. Values in the <tt>min</tt> and <tt>max</tt>
        arrays that correspond to unset bits in the <tt>orientations</tt> field are ignored, and it
        is recommended that they are set to 0.0 when writing the file.</p>
        <h3 id="Object3D">11.19 Object3D</h3>
        <p>
            ObjectType: <i>none (abstract base class)</i>
            <br />
            Superclass data: <i>none</i>
            <br />
            Followed By:</p>
        <blockquote>
            <pre><v2>Int32</v2>            userID;
UInt32           animationTrackCount;

<v2><i>FOR each animation track...</i>

    ObjectIndex    animationTrack;
    
    <i>IF FILE_FORMAT == 2.0, THEN</i>
    
        UInt32         animationTrackIndex;
    
    <i>END</i>

<i>END</i></v2>

UInt32           userParameterCount;

<i>FOR each user parameter...</i>

    <v2>Int32</v2>         parameterID;
    Byte[]        parameterValue;
    
<i>END</i>

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>

    Boolean       animationEnabled;

<i>END</i></v2></pre>
        </blockquote>
        <p>The userID field may be any value.</p>
        <p class="v2">
            Although the definition of the animation track data has changed for a version 1.0
            format file, it will still result in exactly the same data as the file format definition
            in M3G 1.1.</p>
    <p class="v2">
        Animation tracks that are attached to shader uniforms require additional information and
        are not serialized here. Instead, they are serialized separately as part of the
        <a href="#ShaderUniforms">ShaderUniforms</a> object.</p>
    <p>
            The user parameter data contains enough data to create a <tt>java.util.Hashtable</tt>
            object. This contains key/value pairs, with the key being the <tt>parameterID</tt>,
            and the value being the <tt>parameterValue</tt> byte array. The meanings of the
            IDs, and the contents of the byte arrays, are defined by the application and may
            have any value.
        </p>
        <p>
            The behaviour of the <tt>java.util.Hashtable</tt> class does not allow multiple
            objects with the same key. Therefore, duplicate <tt>parameterID</tt> values are
            not allowed and must be reported as an error.
        </p>
        <p>
            If an object has no user parameters, the <tt>userParameterCount</tt> field must
            be 0. In this case, the user object in the resulting Object3D instance must be set
            to <tt>null</tt>, rather than indicating a Hashtable object with no content. The
            Hashtable containing the parameters, if it exists, can be retrieved through the
            API using the <a href="javax/microedition/m3g/Object3D.html#getUserObject%28%29">getUserObject</a>
            method.
        </p>
        <h3 id="PolygonMode">11.20 PolygonMode</h3>
        <p>
            ObjectType: 08
            <br />
            Superclass data: <a href="#Object3D">Object3D</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>Byte          culling;
Byte          shading;
Byte          winding;
Boolean       twoSidedLightingEnabled;
Boolean       localCameraLightingEnabled;
Boolean       perspectiveCorrectionEnabled;

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>

    Float         lineWidth;

<i>END</i></pre></v2>
</blockquote>
        <p>The <tt>culling</tt>, <tt>shading</tt> and <tt>winding</tt> fields must each hold
        a valid <a href="javax/microedition/m3g/PolygonMode.html#field_summary">enumerated value</a>,
        as specified in the class definition. Other values must be treated as errors.</p>
        <h3 id="RayIntersection">11.21 RayIntersection</h3>
        <p><i>Not a serializable class.</i></p>
        
        <h3 id="SkinnedMesh">11.22 SkinnedMesh</h3>
        <p>
            ObjectType: 16
            <br />
            Superclass data: <a href="#Mesh">Mesh</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>ObjectIndex   skeleton;

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>

    Boolean isUsingAddTransform;

<i>END</i>

</v2>UInt32        transformReferenceCount;

<i>FOR each bone reference...</i>

    ObjectIndex   transformNode;
    
    <v2><i>IF isUsingAddTransform, THEN</i>
    
        UInt32        firstVertex;
        UInt32        vertexCount;
        Int32         weight;
    
    <i>END</i></v2>

<i>END</i></pre>
        </blockquote>
        <p class="v2">If the file format is 1.0, we assume that the <tt>isUsingAddTransform</tt> flag is <tt>true</tt>.</p>

        <h3 id="Sprite3D">11.23 Sprite3D</h3>
        <p>
            ObjectType: 18
            <br />
            Superclass data: <a href="#Node">Node</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>ObjectIndex   image;
ObjectIndex   appearance;

Boolean       isScaled;
Int32         cropX;
Int32         cropY;
Int32         cropWidth;
Int32         cropHeight;</pre>
        </blockquote>
        <h3 id="Texture2D">11.24 Texture2D</h3>
        <p>
            ObjectType: 17
            <br />
            Superclass data: <a href="#Texture">Texture</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre><v2><i>IF FILE_FORMAT == 2.0</i>

    ColorRGBA     blendColor;

<i>ELSE</i>

    ColorRGB      blendColor;
    
<i>END</i></v2>

Byte          blending;
Byte          wrappingS;
Byte          wrappingT;

<v2><i>IF FILE_FORMAT == 2.0</i>

    ObjectIndex   combiner;

<i>ELSE</i>

    Byte          levelFilter;
    Byte          imageFilter;

<i>END</i></v2></pre>
        </blockquote>
        <p>The <tt>levelFilter</tt>, <tt>imageFilter</tt>, <tt>wrappingS</tt>, <tt>wrappingT</tt>,
        and <tt>blending</tt> fields must each hold a valid <a href="javax/microedition/m3g/Texture2D.html#field_summary">
            enumerated value</a>, as specified in the class definition. Other values must
        be treated as errors.</p>
        <p class="v2">
            The <tt>image</tt> field from the base class must contain a reference to an Image2D
            object rather than, for example, an ImageCube object.</p>
        <p class="v2">
            The file format already defined for Texture2D in file format version 1.0 complicates
            the treatment of the filter fields. In format 2.0, they are included with the base
            class data, but for format 1.0, they must be serialized after the Texture2D data
            for compatibility reasons. See also <a href="#Texture">Texture</a></p>
        <p class="v2">
            The <tt>blendColor</tt> field has been expanded from a RGB color to an RGBA color for
            format 2.0, because the texture combiner allows use of blend color alpha in the
            blending equation.</p>
        <h3 id="Transform">11.25 Transform</h3>
        <p><i>Not a serializable class.</i></p>
        
        <h3 id="Transformable">11.26 Transformable</h3>
        <p>
            ObjectType: <i>none (abstract base class)</i>
            <br />
            Superclass data: <a href="#Object3D">Object3D</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>Boolean       hasComponentTransform;

<i>IF hasComponentTransform == TRUE, THEN</i>

    Vector3D      translation;
    Vector3D      scale;
    Float32       orientationAngle;
    Vector3D      orientationAxis;
    
<i>END</i>

Boolean       hasGeneralTransform;

<i>IF hasGeneralTransform == TRUE, THEN</i>

    Matrix        transform;
    
<i>END</i></pre>
        </blockquote>
        <p>If either <tt>hasComponentTransform</tt> or <tt>hasGeneralTransform</tt> is <tt>false</tt>,
        the omitted fields will be initialized to their default values (equivalent to an
        identity transform in both cases).</p>
        <h3 id="TriangleStripArray">11.27 TriangleStripArray</h3>
        <p>
            ObjectType: 11
            <br />
            Superclass data: <a href="#IndexBuffer">IndexBuffer</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre><v2><i>IF FILE_FORMAT == 1.0</i></v2>

    UInt32[]      stripLengths;
    
<v2><i>END</i></v2></pre>
        </blockquote>
    <p class="v2">
        Note that the strip information has been moved up to the base class for M3G Version
        2.0, and this class is thus deprecated for M3G2 serialization. We recommend that
        it is not used when serializing out M3G 2.0 files, and that the information is included
        in an IndexBuffer object instead.</p>
    <h3 id="VertexArray">11.28 VertexArray</h3>
        <p>
            ObjectType: 20
            <br />
            Superclass data: <a href="#Object3D">Object3D</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>Byte          componentType;
Byte          componentCount;
Byte          encoding;

UInt16        vertexCount;

<v2><i>FOR each vertex...</i>

    <i>IF componentType == BYTE, THEN</i>
    
        Byte[componentCount] components;
        
    <i>ELSE IF componentType == SHORT, THEN</i>
    
        Int16[componentCount] components;
        
    <i>ELSE IF FILE_FORMAT == 2.0, THEN</i>

        <i>IF componentType == FIXED, THEN</i>
        
            Int32[componentCount] components;

        <i>ELSE IF componentType == HALF, THEN</i>
        
            Float16[componentCount] components;

        <i>ELSE IF componentType == FLOAT, THEN</i>
        
            Float32[componentCount] components;

        <i>END</i>

    <i>END</i>
    
<i>END</i></v2></pre>
        </blockquote>
        <p>The <tt>componentType</tt> and <tt>componentCount</tt> fields must each hold a <a
            href="javax/microedition/m3g/VertexArray.html#VertexArray%28int,%20int,%20int%29">
            valid value</a>, as specified in the constructor definition. Other values must
        be treated as errors.</p>
        <p>
            The <tt>encoding</tt> field indicates the encoding scheme to be used for the keyframe
            data. Currently, only two values are allowed. Other values must be treated as errors.
        </p>
        <ul>
            <li>Encoding 0 indicates that the component values are stored "raw" as the actual values
                to be used.</li>
            <li>Encoding 1 indicates that the component values are stored as differences from the
                previous value. Each component is treated separately, so that the difference is
                taken from the corresponding component in the previous vertex. For the first vertex,
                the previous value is taken to be 0. Decoding proceeds by initializing an accumulator
                to 0 for each component, and adding each value to the accumulator. For integer and
                fixed-point types, in order that the deltas can be represented within the same number
                of bits as the raw values, the accumulators should be the same length as the values
                required (i.e. 8, 16
                <v2>or 32</v2>
                bits) and be allowed to overflow. This also means that the accumulation is not dependent
                on the signed or unsigned nature of the deltas. (For example, the 8-bit sequence
                0, 127, 126 can equally well be represented using deltas of 0, 127, -1 or 0, 127,
                255.)
                <v2>For floating point types, this property does not apply, and must be reported as
                an error. This is because there are sequences of values which cannot be represented
                using delta encoding. In fact, for floating point types, delta encoding is not 
                recommended in any case, since arithmetic errors can accumulate rapidly, especially
                when the sequences have a wide dynamic range. It is also much less likely to result
                in space savings than with integer values.</v2>
            </li>
        </ul>
    <h3 id="VertexBuffer">11.29 VertexBuffer</h3>
        <p>
            ObjectType: 21
            <br />
            Superclass data: <a href="#Object3D">Object3D</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>ColorRGBA     defaultColor;

ObjectIndex   positions;
Float32[3]    positionBias;
Float32       positionScale;

ObjectIndex   normals;
ObjectIndex   colors;

UInt32        texcoordArrayCount;

<i>FOR each texture coordinate array...</i>

   ObjectIndex   texCoords;
   Float32[3]    texCoordBias;
   Float32       texCoordScale;

<i>END</i>

<v2><i>IF FILE_FORMAT == 2.0, THEN</i>
    
    Boolean       isImmutable;

    ObjectIndex   pointSizes;
    Float32       defaultPointSize;

    ObjectIndex   boneIndices;
    ObjectIndex   boneWeights;

    UInt32        namedAttributeCount;
    
    <i>FOR each named attribute array...</i>

        String        name;
        ObjectIndex   attribute;
        Boolean       signed;
        Boolean       normalized;
        Float32[4]    defaultAttributeValue;

    <i>END</i>

<i>END</i></v2></v2></pre>
        </blockquote>
        <p>If a texture coordinate array has only two components, the corresponding <tt>texCoordBias[2]</tt>
        element must be 0.0.</p>
        <p>
            Null texture coordinate arrays are never serialized, regardless of their position.
            A single texture coordinate array will therefore always be serialized as belonging
            to texturing unit 0, regardless of its original unit it was assigned to.
        </p>
        <p>
            There are as many references in the texture coordinates array as there are active
            texture units for this geometry. The texture coordinate references are loaded sequentially
            from texture unit 0. If the implementation supports more texture units than are
            specified, these are left in their default, inactive state, with a null texture
            coordinate reference and an undefined bias and scale.
        </p>
        <p>
            If more texture coordinate references are specified than are supported by the implementation,
            then this must be treated as an error, as it would be in the API. The application
            can then decide on an appropriate course of action to handle this case.
        </p>
    <p class="v2">
        If the <tt>isImmutable</tt> flag is <tt>true</tt>, then the required effect is equivalent
        to calling <tt>commit</tt> on the object after loading is complete.</p>
    <p class="v2">
            If a named attribute has fewer than 4 components, only those components are used
            from the <tt>defaultAttributeValue</tt> field; the others are ignored. It is recommended
            that any unused components are set to 0.0 when writing the file.</p>
    <h3 id="World">11.30 World</h3>
        <p>
            ObjectType: 22
            <br />
            Superclass data: <a href="#Group">Group</a>
            <br />
            Followed By:</p>
        <blockquote>
            <pre>ObjectIndex   activeCamera;
ObjectIndex   background;</pre>
        </blockquote>
        <h2 class="v2" id="PerClassData20">
            12 Per-Class Data for Format 2.0
        </h2>
        <p class="v2">
            The data for each new class in the Version 2.0 file format is now presented in alphabetical
            order. The same rules and observations apply to these classes as to the 1.0 classes
            documented in Section 11. These classes must not appear in a 1.0 file format file,
            except where they are base classes for a class listed in Section 11.</p>
    <h3 class="v2" id="AnimationEvent">
        12.1 AnimationEvent</h3>
    <p class="v2">
        <i>Not a serializable class.</i></p>
        
    <h3 class="v2" id="AppearanceBase">12.2 AppearanceBase</h3>
        <p class="v2">
            ObjectType: <i>none (abstract base class)</i>
            <br />
            Superclass data: <a href="#Object3D">Object3D</a>
            <br />
            Followed By:</p>
            <blockquote>
                <pre class="v2"><i>IF FILE_FORMAT == 1.0, THEN</i>
                
    Byte          layer;

<i>ELSE</i>

    SByte         layer;

<i>END</i>

ObjectIndex   compositingMode;

<i>IF FILE_FORMAT == 2.0, THEN</i>

    ObjectIndex   polygonMode;
    Boolean       isDepthSortEnabled;

<i>END</i></pre>
        </blockquote>
    
    <p class="v2">
        The file format already defined for Appearance in file format version 1.0 complicates
        the treatment of the <tt>polygonMode</tt> field. In format 2.0, it is included with
        the base class data, but for format 1.0, it must be serialized with the Appearance
        data for compatibility reasons. See also <a href="#Appearance">Appearance</a></p>
    <p class="v2">Similarly, the file format 1.0 incorrectly specified that the <tt>layer</tt>
        field should be an unsigned byte, despite the API allowing negative values. This
        behavior is kept for compatibility reasons, but in format 2.0 a signed byte is
        used to allow negative values also. The <tt>layer</tt> field in either case must
        contain a valid
        <a href="javax/microedition/m3g/AppearanceBase.html#setLayer(int)">layer number</a>,
        as specified in the class definition.</p>    
    <h3 id="Blender" class="v2">
        12.3 Blender</h3>
    <p class="v2">
        ObjectType: 23
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">Byte          funcAlpha;
Byte          srcAlpha;
Byte          dstAlpha;
    
Byte          funcColor;
Byte          srcColor;
Byte          dstColor;
    
ColorRGBA     blendColor;</pre>
    </blockquote>
    <p class="v2">The <tt>funcAlpha</tt>, <tt>srcAlpha</tt>, <tt>dstAlpha</tt>,
<tt>funcColor</tt>, <tt>srcColor</tt>, and <tt>dstColor</tt> fields must hold a valid <a
 href="javax/microedition/m3g/Blender.html#field_summary">enumerated
value</a>, as specified in the class definition. 
Other values must be treated as errors.</p>
    <h3 id="Collisions" class="v2">
        12.4 Collisions</h3>
    <p class="v2">
        <i>Not a serializable class.</i></p>
    <h3 class="v2" id="DynamicImage2D">12.5 DynamicImage2D</h3>
    <p class="v2">
        ObjectType: 24
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
<em>Nothing</em>
    </blockquote>
        <p class="v2">
        The only data stored within a DynamicImage2D is a Java object referring
        to a dynamic data source. Since these cannot be specified with serializable data
        (they have no uniform naming scheme, unlike files), it is not possible to serialize
        the contents of a DynamicImage2D. However, it is still useful to include the presence
        of a DynamicImage2D in the serialized scene graph, so that it can later be attached
        to a dynamic image source. This avoids having to use workarounds such as serializing
        a small dummy Image2D, and replacing it with the desired DynamicImage2D after loading.</p>
    <h3 class="v2" id="FragmentShader">12.6 FragmentShader</h3>
    <p class="v2">
        ObjectType: 25
        <br />
        Superclass data: <a href="#Shader">Shader</a>
        <br />
        Followed By:</p>
    <blockquote>
        <p class="v2">
            <i>Nothing</i>
        </p>
    </blockquote>

    <h3 class="v2" id="ImageBase">12.7 ImageBase</h3>
    <p class="v2">
        ObjectType: <i>none (abstract base class)</i>
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2"><i>IF FORMAT == 2.0, THEN</i>
    
    Int32         format;

<i>ELSE</i>

    Byte          format;
    
<i>END</i>

Boolean       isMutable;
UInt32        width;
UInt32        height;</pre>
    </blockquote>
    <p class="v2">
        Although this class exists only in version 2.0, it is compatible with version 1.0.
        When combined with the additional data in Image2D, the resulting data stream is
        completely compatible with version 1.0.</p>
    <p class="v2">
        The <tt>format</tt> field must hold a valid <a href="javax/microedition/m3g/ImageBase.html#field_summary">
            enumerated value</a>, as specified in the class definition. Other values must
        be treated as errors.</p>
    <h3 class="v2" id="ImageCube">12.8 ImageCube</h3>
    <p class="v2">
        ObjectType: 26
        <br />
        Superclass data: <a href="#ImageBase">ImageBase</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2"><i>IF isMutable == false, THEN</i>

    <i>FOR each face of the cube...</i>
        
        Byte[]        pixels;
        Byte          mipmapCount;
        
        <i>FOR each specified mipmap level...</i>
        
            Byte[]        mipmapPixels;
        
        <i>END</i>        
    
    <i>END</i>

<i>END</i></pre>
    </blockquote>
    <p class="v2">
        Each face of the cube has width * height pixels' worth of data, and the faces are
        serialized in the same order as they are supplied in the <a href="javax/microedition/m3g/ImageCube.html#ImageCube(int, int, byte[][][])">
        immutable constructor</a>.</p>
    <p class="v2">
        The <tt>format</tt> field from the base class must hold a valid <a href="javax/microedition/m3g/ImageCube.html#constructor_detail">
        enumerated value</a>, as specified in the ImageCube constructor definition. Other values must
        be treated as errors.</p>
 
    <p class="v2">
        The rules for loading mipmap levels are the same as those defined for the <a href="file-format.html#Image2D">Image2D</a> class.</p>

    <h3 id="PointSpriteMode" class="v2">12.9 PointSpriteMode</h3>
    <p class="v2">
        ObjectType: 28
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">Float32       pointFadeThreshold;
Float32       pointAttenuationA;
Float32       pointAttenuationB;
Float32       pointAttenuationC;
Float32       pointSizeClampMin;
Float32       pointSizeClampMax;</pre>
    </blockquote>
    <h3 class="v2" id="RenderPass">12.10 RenderPass</h3>
    <p class="v2">
        ObjectType: 29
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">ObjectIndex   scene;
ObjectIndex   camera;
ObjectIndex   background;
ObjectIndex   target;
UInt32        flags;
Float32       depthRangeNear;
Float32       depthRangeFar;
Boolean       isViewportSet;

<i>IF isViewportSet == TRUE, THEN</i>
    
    Int32         viewportX;
    Int32         viewportY;
    Int32         viewportWidth;
    Int32         viewportHeight;
    
<i>END</i>
</pre>
    </blockquote>
    <p class="v2">
        In the class, the <tt>target</tt> may be any renderable surface. In the Loader,
        the only valid rendering targets are <a href="#Image2D">Image2D</a> or <a href="#ImageCube">
            ImageCube</a>.</p>
    <h3 class="v2" id="RenderTarget">12.11 RenderTarget</h3>
    <p class="v2">
        ObjectType: 30
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">ObjectIndex   target;
Byte          targetLevel;
Byte          targetFace;
</pre>
    </blockquote>
    <p class="v2">
        If <tt>target</tt> is an <a href="#ImageCube">ImageCube</a>, then the 
        <tt>targetFace</tt> field must hold a valid <a href="javax/microedition/m3g/ImageCube.html#constructor_detail">
        enumerated value</a>, as specified in the class definition. Other values must
        be treated as errors.</p>
    <p class="v2"> For other target types, it is recommended that the
        <tt>targetFace</tt> field is set to 0 when writing the file.</p>
    <h3 class="v2" id="Shader">12.12 Shader</h3>
    <p class="v2">
        ObjectType: <i>none (abstract base class)</i>
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">String  source;</pre>
    </blockquote>
    <h3 class="v2" id="ShaderAppearance">12.13 ShaderAppearance</h3>
    <p class="v2">
        ObjectType: 31
        <br />
        Superclass data: <a href="#AppearanceBase">AppearanceBase</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">ObjectIndex   shaderProgram;
ObjectIndex[] shaderUniforms;
Boolean       isValidateEnabled;</pre>
    </blockquote>
    <p class="v2">
        These are simply references to each of the objects aggregated together to form an
        appearance.
    </p>
    <h3 class="v2" id="ShaderException">12.14 ShaderException</h3>
    <p class="v2">
        <i>Not a serializable class.</i></p>
        
    <h3 class="v2" id="ShaderProgram">12.15 ShaderProgram</h3>
    <p class="v2">
        ObjectType: 32
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">ObjectIndex   fragmentShader;
ObjectIndex   vertexShader;</pre>
    </blockquote>
    <p class="v2">
        These are simply references to each of the shader objects aggregated together to
        form a shader program, together with a flag that enables or disables strict shader validation.
    </p>
    <h3 class="v2" id="ShaderUniforms">12.16 ShaderUniforms</h3>
    <p class="v2">
        ObjectType: 33
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">UInt32        uniformCount;
  
<i>FOR each uniform...</i>
  
    String        name;
    UInt16        type;
    UInt16        bindingType;
    UInt32        length;
    
    <i>IF bindingType == 0, THEN</i>

        <i>IF type == BOOL, THEN</i>
        
            Boolean[length]      value;
        
        <i>ELSE IF type == BVEC2, THEN</i>
        
            Boolean[2 * length]  value;
        
        <i>ELSE IF type == BVEC3, THEN</i>
        
            Boolean[3 * length]  value;
        
        <i>ELSE IF type == BVEC4, THEN</i>
        
            Boolean[4 * length]  value;
        
        <i>ELSE IF type == INT, THEN</i>
        
            Int32[length]        value;
        
        <i>ELSE IF type == IVEC2, THEN</i>
        
            Int32[2 * length]    value;
        
        <i>ELSE IF type == IVEC3, THEN</i>
        
            Int32[3 * length]    value;
        
        <i>ELSE IF type == IVEC4, THEN</i>
        
            Int32[4 * length]    value;
        
        <i>ELSE IF type == FLOAT, THEN</i>
        
            Float32[length]      value;
        
        <i>ELSE IF type == VEC2, THEN</i>
        
            Float32[2 * length]  value;
        
        <i>ELSE IF type == VEC3, THEN</i>
        
            Float32[3 * length]  value;
        
        <i>ELSE IF type == VEC4, THEN</i>
        
            Float32[4 * length]  value;
        
        <i>ELSE IF type == MAT2, THEN</i>
        
            Float32[4 * length]  value;
        
        <i>ELSE IF type == MAT3, THEN</i>
        
            Float32[9 * length]  value;
        
        <i>ELSE IF type == MAT3X4, THEN</i>
        
            Float32[12 * length] value;
        
        <i>ELSE IF type == MAT4, THEN</i>
        
            Float32[16 * length] value;
        
        <i>ELSE IF type == SAMPLER_2D, THEN</i>
        
            ObjectIndex[length]  value;

        <i>ELSE IF type == SAMPLER_CUBE, THEN</i>
        
            ObjectIndex[length]  value;

        <i>END</i>
    
        UInt32    trackCount;

        <i>FOR each of trackCount tracks...</i>

            ObjectIndex   animationTrack;
            UInt32        channelIndex;
        
        <i>END</i>

    <i>ELSE IF bindingType == 1, THEN</i>
    
        ForwardIndex[length]  nodeFrom;
        ForwardIndex          nodeTo;
    
    <i>ELSE IF bindingType == 2, THEN</i>
    
        ForwardIndex          nodeFrom;
        ForwardIndex[length]  nodeTo;
    
    <i>ELSE IF bindingType == 3, THEN</i>

        ForwardIndex[length]  source;
        UInt32                property;

    <i>END</i>

<i>END</i>

</pre>
    </blockquote>
    <p class="v2">
        The <tt>type</tt> field must hold a valid <a
        href="javax/microedition/m3g/ShaderVariable.html#field_summary">enumerated
        value</a>, as specified in the ShaderVariable class description.  Other values must
        be treated as errors.</p>
    <p class="v2">
        The <tt>bindingType</tt> field indicates the kind of value bound to the uniform's
        value. Only the nominated values above are allowed. Other values must be treated
        as errors.</p>
    <ul class="v2">
        <li>Type 0 indicates that the uniform's value is specified directly. For details, see the various API methods called
            <a href="javax/microedition/m3g/ShaderUniforms.html#setUniformValue(int,%20boolean)">setUniformValue</a>.</li>
        <li>Types 1 and 2 indicates that the uniform is bound to a transformation in the scene graph.
            If only a single transformation is bound, then both of these methods are equivalent.
            For details, see API methods
            <a href="javax/microedition/m3g/ShaderUniforms.html#bindTransform(int,%20javax.microedition.m3g.Node,%20javax.microedition.m3g.Node)">bindTransform</a> and 
            <a href="javax/microedition/m3g/ShaderUniforms.html#bindTransformArray(int,%20javax.microedition.m3g.Node[],%20javax.microedition.m3g.Node)"> bindTransformArray</a>.</li>
        <li>Type 3 indicates that the uniform is bound to an object property. For details, see API methods 
            <a href="javax/microedition/m3g/ShaderUniforms.html#bindUniformValue(int,%20javax.microedition.m3g.Object3D,%20int)">bindUniformValue</a> and
            <a href="javax/microedition/m3g/ShaderUniforms.html#bindUniformValue(int,%20javax.microedition.m3g.Object3D[],%20int)">bindUniformValueArray</a>.</li>
    </ul>
    <p class="v2">
        The <tt>length</tt> field indicates the dimension of array uniforms, or 0 if the uniform is a scalar value.
        In this case, the length is assumed to be 1 when calculating the length of the arrays of serialized data.</p>
    <p class="v2">The API method <a href="javax/microedition/m3g/ShaderUniforms.html#addAnimationTrack(int,%20javax.microedition.m3g.AnimationTrack,%20int)">
        addAnimationTrack</a> can be used to associate animation tracks with uniforms. If this has been used,
        then the animation tracks associated with a particular uniform will be serialized. If the uniform
        has no animation tracks attached to it, then the <tt>trackCount</tt> field will be 0. Note that these
        only appear if the <tt>bindingType</tt> field is 0, since other binding types preclude the animation
        of the uniform. If animation tracks are present, but not attached to uniforms, then they will be
        serialized as part of the <a href="#Object3D">Object3D</a> data as usual.</p>
    <h3 id="ShaderVariable" class="v2">
        12.17 ShaderVariable</h3>
    <p class="v2">
        <i>Not a serializable class.</i></p>
    <h3 id="Stencil" class="v2">
        12.18 Stencil</h3>
    <p class="v2">
        ObjectType: 34
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">
Int16         stencilFuncFront;
Int32         stencilRefFront;
Int32         stencilMaskFront;

Int32         stencilWriteMaskFront;

Byte          stencilFailOpFront;
Byte          stencilPassDepthFailOpFront;
Byte          stencilPassDepthPassOpFront;

Int16         stencilFuncBack;
Int32         stencilRefBack;
Int32         stencilMaskBack;

Int32         stencilWriteMaskBack;

Byte          stencilFailOpBack;
Byte          stencilPassDepthFailOpBack;
Byte          stencilPassDepthPassOpBack;
</pre>
    </blockquote>
    <p class="v2">The <tt>stencilFuncFront</tt>, <tt>stencilFailOpFront</tt>, 
        <tt>stencilPassDepthFailOpFront</tt>, <tt>stencilPassDepthPassOpFront</tt>,
        <tt>stencilFuncBack</tt>, <tt>stencilFailOpBack</tt>, 
        <tt>stencilPassDepthFailOpBack</tt> and <tt>stencilPassDepthPassOpBack</tt>
        fields must hold a valid <a
        href="javax/microedition/m3g/Stencil.html#field_summary">enumerated
        value</a>, as specified in the class definition. 
        Other values must be treated as errors.</p>
    <h3 class="v2" id="Texture">12.19 Texture</h3>
    <p class="v2">
        ObjectType: <i>none (abstract base class)</i>
        <br />
        Superclass data: <a href="#Transformable">Transformable</a>
        <br />
        Followed by:</p>
    <blockquote>
        <pre class="v2">ObjectIndex   image;

<i>IF FILE_FORMAT == 2.0, THEN</i>

    Byte          levelFilter;
    Byte          imageFilter;

<i>END</i></pre>
    </blockquote>
    <p class="v2">
        The <tt>levelFilter</tt> and <tt>imageFilter</tt> fields must each hold a valid
        <a href="javax/microedition/m3g/Texture.html#field_summary">enumerated value</a>,
        as specified in the class definition. Other values must be treated as errors.</p>
    <p class="v2">
        The file format already defined for Texture2D in file format version 1.0 complicates
        the treatment of the filter fields. In format 2.0, they are included with the base
        class data, but for format 1.0, they must be serialized after the Texture2D data
        for compatibility reasons. See also <a href="#Texture2D">Texture2D</a></p>
    <h3 class="v2" id="TextureCombiner">12.20 TextureCombiner</h3>
    <p class="v2">
        ObjectType: 35
        <br />
        Superclass data: <a href="#Object3D">Object3D</a>
        <br />
        Followed By:</p>
    <blockquote>
        <pre class="v2">Byte          colorFunction;
Byte          colorScale;
UInt16        colorSource0;

<i>IF colorFunction != REPLACE, THEN</i>

    UInt16        colorSource1;
    
    <i>IF colorFunction == INTERPOLATE, THEN</i>
    
        UInt16        colorSource2;
        
    <i>END</i>

<i>END</i>

Byte          alphaFunction;
Byte          alphaScale;
UInt16        alphaSource0;

<i>IF alphaFunction != REPLACE, THEN</i>

    UInt16        alphaSource1;
    
    <i>IF alphaFunction == INTERPOLATE, THEN</i>
    
        UInt16        alphaSource2;
        
    <i>END</i>

<i>END</i>

</pre>
    </blockquote>
    <p class="v2">
        The fields must each hold a valid <a href="javax/microedition/m3g/TextureCombiner.html#field_summary">
            enumerated value</a>, as specified in the class definition. Other values must
        be treated as errors.</p>
    <h3 class="v2" id="TextureCube">12.21 TextureCube</h3>
    <p class="v2">
        ObjectType: 36
        <br />
        Superclass data: <a href="#Texture">Texture</a>
        <br />
        Followed By:</p>
    <blockquote>
        <p class="v2">
            <i>Nothing</i></p>
    </blockquote>
    <p class="v2">
        The <tt>image</tt> field from the base class must contain a reference to an ImageCube
        object rather than a "plain" Image2D.</p>
    <h3 class="v2" id="VertexShader">12.22 VertexShader</h3>
    <p class="v2">
        ObjectType: 37
        <br />
        Superclass data: <a href="#Shader">Shader</a>
        <br />
        Followed By:</p>
    <blockquote>
        <p class="v2">
            <i>Nothing</i></p>
    </blockquote>
    <h2 class="SectionTitle" id="ObjectTypeValues">13 ObjectType Values</h2>
    <p>This list shows what object type a specific ObjectType value maps to.
    <v2>Objects already present in the version 1.0 file
format do not have their type IDs changed, even if they are
now derived differently or have changed their internal
data format. Objects present only in version 2.0 of the file
format have types assigned after the version 1.0 objects.</v2></p>
    <blockquote>
        <table border="1" cellpadding="3" cellspacing="0" class="Table">
            <tbody>
                <tr>
                    <td>
                        <b>ObjectType value</b></td>
                    <td>
                        <b>Object Type</b></td>
                </tr>
                <tr>
                    <td>
                        00</td>
                    <td>
                        <a href="#Header">Header Object</a></td>
                </tr>
                <tr>
                    <td>
                        01</td>
                    <td>
                        <a href="#AnimationController">AnimationController</a></td>
                </tr>
                <tr>
                    <td>
                        02</td>
                    <td>
                        <a href="#AnimationTrack">AnimationTrack</a></td>
                </tr>
                <tr>
                    <td>
                        03</td>
                    <td>
                        <a href="#Appearance">Appearance</a></td>
                </tr>
                <tr>
                    <td>
                        04</td>
                    <td>
                        <a href="#Background">Background</a></td>
                </tr>
                <tr>
                    <td>
                        05</td>
                    <td>
                        <a href="#Camera">Camera</a></td>
                </tr>
                <tr>
                    <td>
                        06</td>
                    <td>
                        <a href="#CompositingMode">CompositingMode</a></td>
                </tr>
                <tr>
                    <td>
                        07</td>
                    <td>
                        <a href="#Fog">Fog</a></td>
                </tr>
                <tr>
                    <td>
                        08</td>
                    <td>
                        <a href="#PolygonMode">PolygonMode</a></td>
                </tr>
                <tr>
                    <td>
                        09</td>
                    <td>
                        <a href="#Group">Group</a></td>
                </tr>
                <tr>
                    <td>
                        10</td>
                    <td>
                        <a href="#Image2D">Image2D</a></td>
                </tr>
                <tr>
                    <td>
                        11</td>
                    <td>
                        <a href="#TriangleStripArray">TriangleStripArray</a></td>
                </tr>
                <tr>
                    <td>
                        12</td>
                    <td>
                        <a href="#Light">Light</a></td>
                </tr>
                <tr>
                    <td>
                        13</td>
                    <td>
                        <a href="#Material">Material</a></td>
                </tr>
                <tr>
                    <td>
                        14</td>
                    <td>
                        <a href="#Mesh">Mesh</a></td>
                </tr>
                <tr>
                    <td>
                        15</td>
                    <td>
                        <a href="#MorphingMesh">MorphingMesh</a></td>
                </tr>
                <tr>
                    <td>
                        16</td>
                    <td>
                        <a href="#SkinnedMesh">SkinnedMesh</a></td>
                </tr>
                <tr>
                    <td>
                        17</td>
                    <td>
                        <a href="#Texture2D">Texture2D</a></td>
                </tr>
                <tr>
                    <td>
                        18</td>
                    <td>
                        <a href="#Sprite3D">Sprite3D</a></td>
                </tr>
                <tr>
                    <td>
                        19</td>
                    <td>
                        <a href="#KeyframeSequence">KeyframeSequence</a></td>
                </tr>
                <tr>
                    <td>
                        20</td>
                    <td>
                        <a href="#VertexArray">VertexArray</a></td>
                </tr>
                <tr>
                    <td>
                        21</td>
                    <td>
                        <a href="#VertexBuffer">VertexBuffer</a></td>
                </tr>
                <tr>
                    <td>
                        22</td>
                    <td>
                        <a href="#World">World</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        23</td>
                    <td>
                        <a href="#Blender">Blender</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        24</td>
                    <td>
                        <a href="#DynamicImage2D">DynamicImage2D</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        25</td>
                    <td>
                        <a href="#FragmentShader">FragmentShader</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        26</td>
                    <td>
                        <a href="#ImageCube">ImageCube</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        27</td>
                    <td>
                        <a href="#IndexBuffer">IndexBuffer</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        28</td>
                    <td>
                        <a href="#PointSpriteMode">PointSpriteMode</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        29</td>
                    <td>
                        <a href="#RenderPass">RenderPass</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        30</td>
                    <td>
                        <a href="#RenderTarget">RenderTarget</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        31</td>
                    <td>
                        <a href="#ShaderAppearance">ShaderAppearance</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        32</td>
                    <td>
                        <a href="#ShaderProgram">ShaderProgram</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        33</td>
                    <td>
                        <a href="#ShaderUniforms">ShaderUniforms</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        34</td>
                    <td>
                        <a href="#Stencil">Stencil</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        35</td>
                    <td>
                        <a href="#TextureCombiner">TextureCombiner</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        36</td>
                    <td>
                        <a href="#TextureCube">TextureCube</a></td>
                </tr>
                <tr class="v2">
                    <td>
                        37</td>
                    <td>
                        <a href="#VertexShader">VertexShader</a></td>
                </tr>
                <tr>
                    <td>
                        <v2>38... 252</v2></td>
                    <td>
                        Reserved for use in future versions of the file format</td>
                </tr>
                <tr>
                    <td>
                        253</td>
                    <td>
                        <a href="#ExternalReferenceObject">External Object Reference</a></td>
                </tr>
                <tr>
                    <td>
                        254</td>
                    <td>
                        <a href="#ExternalReferenceImage">External Image Reference</a></td>
                </tr>
                <tr>
                    <td>
                        255</td>
                    <td>
                        <a href="#ExternalReference">External Reference</a></td>
                </tr>
            </tbody>
        </table>
    </blockquote>
    <p>Note that Object3D, Transformable, Node, IndexBuffer,
    <v2>AppearanceBase, ImageBase, Shader, and Texture</v2>
    are abstract classes and cannot be instantiated directly. They therefore do not
    appear in this list.</p>
</body>
</html>
